Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MMM-PublicTransportHafas.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. * Update by AgP42 the 18/07/2018
  3. *
  4. * Modification added :
  5. * - Management of a PIR sensor with the module MMM-PIR-Sensor (by PaViRo). In case PIR module detect no user,
  6. * the update of the ToDoIst is stopped and will be requested again at the return of the user
  7. * - Management of the "module.hidden" by the core system : same behaviour as "User_Presence" by the PIR sensor
  8. * - Possibility to add the last update time from server at the end of the module.
  9. * This can be configured using "displayLastUpdate" and "displayLastUpdateFormat"
  10. * */
  11. "use strict";
  12. //UserPresence Management (PIR sensor)
  13. var UserPresence = true; //true by default, so no impact for user without a PIR sensor
  14. Module.register("MMM-PublicTransportHafas", {
  15. // default values
  16. defaults: {
  17. // Module misc
  18. name: "MMM-PublicTransportHafas",
  19. hafasProfile: "db", // Which HAFAS profile should be used?
  20. hidden: false,
  21. updatesEvery: 120, // How often should the table be updated in s?
  22. // Header
  23. headerPrefix: "",
  24. headerAppendix: "",
  25. // Display last update time
  26. displayLastUpdate: false, // Add or not a line after the tasks with the last server update time
  27. displayLastUpdateFormat: 'dd - HH:mm:ss', // Format to display the last update. See Moment.js documentation for all display possibilities
  28. // Departures options
  29. direction: "", // Show only departures heading to this station. (A station ID.)
  30. ignoredLines: [], // Which lines should be ignored? (comma-separated list of line names)
  31. excludedTransportationTypes: [], // Which transportation types should not be shown on the mirror? (comma-separated list of types) possible values: "tram", "bus", "suburban", "subway", "regional" and "national"
  32. timeToStation: 10, // How long do you need to walk to the Station? (in minutes)
  33. timeInFuture: 40, // Show departures for the next *timeInFuture* minutes.
  34. // Look and Feel
  35. marqueeLongDirections: true, // Use Marquee effect for long station names?
  36. replaceInDirections: {}, // key-value pairs which are used to replace `key` by `value` in the displayed directions
  37. showColoredLineSymbols: true, // Want colored line symbols?
  38. useColorForRealtimeInfo: true, // Want colored real time information (timeToStation, early)?
  39. showAbsoluteTime: true, // How should the departure time be displayed? "15:10" (absolute) or "in 5 minutes" (relative)
  40. showTableHeaders: true, // Show table headers?
  41. showTableHeadersAsSymbols: true, // Table Headers as symbols or written?
  42. tableHeaderOrder: [ "time", "line", "direction" ], // In which order should the table headers appear? (add "platform" if you like)
  43. maxUnreachableDepartures: 0, // How many unreachable departures should be shown?
  44. maxReachableDepartures: 7, // How many reachable departures should be shown?
  45. fadeUnreachableDepartures: true,
  46. fadeReachableDepartures: true,
  47. fadePointForReachableDepartures: 0.25,
  48. customLineStyles: "", // Prefix for the name of the custom css file. ex: Leipzig-lines.css (case sensitive)
  49. showOnlyLineNumbers: false, // Display only the line number instead of the complete name, i. e. "11" instead of "STR 11"
  50. animationSpeed: 1500 // Refresh animation speed in milliseconds
  51. },
  52. start: function () {
  53. Log.info("Starting module: " + this.name + " with identifier: " + this.identifier);
  54. this.ModulePublicTransportHafasHidden = false; // By default we display the module (if no carousel or other module)
  55. this.updatesIntervalID = 0; // To stop and start auto update for each module instance
  56. this.lastUpdate = 0; // Timestamp of the last module update. set at 0 at start-up
  57. this.departures = [];
  58. this.initialized = false;
  59. this.error = {};
  60. this.sanitzeConfig();
  61. if (!this.config.stationID) {
  62. Log.error("stationID not set! " + this.config.stationID);
  63. this.error.message = this.translate("NO_STATION_ID_SET");
  64. return;
  65. }
  66. let fetcherOptions = {
  67. identifier: this.identifier,
  68. hafasProfile: this.config.hafasProfile,
  69. stationID: this.config.stationID,
  70. timeToStation: this.config.timeToStation,
  71. timeInFuture: this.config.timeInFuture,
  72. direction: this.config.direction,
  73. ignoredLines: this.config.ignoredLines,
  74. excludedTransportationTypes: this.config.excludedTransportationTypes,
  75. maxReachableDepartures: this.config.maxReachableDepartures,
  76. maxUnreachableDepartures: this.config.maxUnreachableDepartures
  77. };
  78. this.sendSocketNotification("CREATE_FETCHER", fetcherOptions);
  79. },
  80. //Modif AgP42 - 12/07/2018
  81. suspend: function() { // Core function called when the module is hidden
  82. this.ModulePublicTransportHafasHidden = true; // Module hidden
  83. // Log.log("Function suspend - Module PublicTransportHafas is hidden " + this.config.stationName);
  84. this.GestionUpdateIntervalHafas(); // Call the function which manages all the cases
  85. },
  86. resume: function() { // Core function called when the module is displayed
  87. this.ModulePublicTransportHafasHidden = false;
  88. // Log.log("Function working - Module PublicTransportHafas is displayed " + this.config.stationName);
  89. this.GestionUpdateIntervalHafas();
  90. },
  91. notificationReceived: function(notification, payload) {
  92. if (notification === "USER_PRESENCE") { // Notification sent by the MMM-PIR-Sensor module. See its doc.
  93. // Log.log("NotificationReceived USER_PRESENCE = " + payload);
  94. UserPresence = payload;
  95. this.GestionUpdateIntervalHafas();
  96. }
  97. },
  98. GestionUpdateIntervalHafas: function() {
  99. if (UserPresence === true && this.ModulePublicTransportHafasHidden === false){ // Make sure to have a user present in front of the screen (PIR sensor) and that the module is displayed
  100. let self = this;
  101. // Log.log(this.config.stationName + " is displayed and user present! Update it");
  102. // Update now and start again the update timer
  103. this.startFetchingLoop(this.config.updatesEvery);
  104. }else{ // (UserPresence = false OU ModulePublicTransportHafasHidden = true)
  105. // Log.log("No one is watching: Stop the update!" + this.config.stationName);
  106. clearInterval(this.updatesIntervalID); // Stop the current update interval
  107. this.updatesIntervalID = 0; // Reset the variable
  108. }
  109. },
  110. getDom: function () {
  111. let domBuilder = new PTHAFASDomBuilder(this.config);
  112. if (this.hasErrors()) {
  113. return domBuilder.getSimpleDom(this.error.message);
  114. }
  115. if (!this.initialized) {
  116. return domBuilder.getSimpleDom(this.translate("LOADING"));
  117. }
  118. let headings = {
  119. time: this.translate("PTH_DEPARTURE_TIME"),
  120. line: this.translate("PTH_LINE"),
  121. direction: this.translate("PTH_TO"),
  122. platform: this.translate("PTH_PLATFORM")
  123. };
  124. let noDeparturesMessage = this.translate("PTH_NO_DEPARTURES");
  125. let wrapper = domBuilder.getDom(this.departures, headings, noDeparturesMessage);
  126. // display the update time at the end, if defined so by the user config
  127. if(this.config.displayLastUpdate){
  128. let updateinfo = document.createElement("div");
  129. updateinfo.className = "xsmall light align-left";
  130. updateinfo.innerHTML = "Update: " + moment.unix(this.lastUpdate).format(this.config.displayLastUpdateFormat);
  131. wrapper.appendChild(updateinfo);
  132. }
  133. return wrapper;
  134. },
  135. getStyles: function () {
  136. let styles = [
  137. this.file("css/styles.css"),
  138. "font-awesome.css"
  139. ];
  140. if (this.config.customLineStyles !== "") {
  141. let customStyle = "css/" + this.config.customLineStyles + "-lines.css";
  142. styles.push(this.file(customStyle));
  143. }
  144. return styles;
  145. },
  146. getScripts: function () {
  147. return [
  148. "moment.js",
  149. this.file("core/PTHAFASDomBuilder.js"),
  150. this.file("core/PTHAFASTableBodyBuilder.js")
  151. ];
  152. },
  153. getTranslations: function() {
  154. return {
  155. en: "translations/en.json",
  156. de: "translations/de.json"
  157. };
  158. },
  159. socketNotificationReceived: function (notification, payload) {
  160. if (!this.isForThisStation(payload)) {
  161. return;
  162. }
  163. switch (notification) {
  164. case "FETCHER_INITIALIZED":
  165. this.initialized = true;
  166. this.startFetchingLoop(this.config.updatesEvery);
  167. break;
  168. case "DEPARTURES_FETCHED":
  169. //AgP
  170. if(this.config.displayLastUpdate){
  171. this.lastUpdate = Date.now() / 1000 ; //save the timestamp of the last update to be able to display it
  172. }
  173. Log.log("TransportHafas update OK, station : " + this.config.stationName + " at : "
  174. + moment.unix(this.lastUpdate).format(this.config.displayLastUpdateFormat));
  175. //this.sendNotification("SHOW_ALERT",{type:"notification",message:"Update Transport Berlin recue"});
  176. // reset error object
  177. this.error = {};
  178. this.departures = payload.departures;
  179. this.updateDom(this.config.animationSpeed);
  180. this.sendNotification('TRANSPORT_HAFAS', payload.departures)
  181. break;
  182. case "FETCH_ERROR":
  183. this.error = payload.error;
  184. this.departures = [];
  185. this.updateDom(this.config.animationSpeed);
  186. break;
  187. }
  188. },
  189. isForThisStation: function (payload) {
  190. return payload.identifier === this.identifier;
  191. },
  192. sanitzeConfig: function () {
  193. if (this.config.updatesEvery < 30) {
  194. this.config.updatesEvery = 30;
  195. }
  196. if (this.config.timeToStation < 0) {
  197. this.config.timeToStation = 0;
  198. }
  199. if (this.config.timeInFuture < this.config.timeToStation + 30) {
  200. this.config.timeInFuture = this.config.timeToStation + 30;
  201. }
  202. if (this.config.maxUnreachableDepartures < 0) {
  203. this.config.maxUnreachableDepartures = 0;
  204. }
  205. if (this.config.maxReachableDepartures < 0) {
  206. this.config.maxReachableDepartures = this.defaults.maxReachableDepartures;
  207. }
  208. },
  209. startFetchingLoop: function(interval) {
  210. // start immediately ...
  211. this.sendSocketNotification("FETCH_DEPARTURES", this.identifier);
  212. // ... and then repeat in the given interval
  213. // Log.log("Hello, update module Transport requested! (non-recurring)");
  214. // this.sendNotification("SHOW_ALERT",{type:"notification",message:"Update Transport Berlin requested"});
  215. if (this.updatesIntervalID === 0){//if this instance as no auto update defined, then we create one. Otherwise : nothing.
  216. this.updatesIntervalID = setInterval(() => {
  217. this.sendSocketNotification("FETCH_DEPARTURES", this.identifier);
  218. }, interval * 1000);
  219. }
  220. },
  221. hasErrors: function () {
  222. return (Object.keys(this.error).length > 0);
  223. },
  224. });