-
Notifications
You must be signed in to change notification settings - Fork 3
/
MMM-MyTransitTime.js
executable file
·166 lines (143 loc) · 5.46 KB
/
MMM-MyTransitTime.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
Module.register("MMM-MyTransitTime", {
// Default module config.
defaults: {
apiKey: "YOUR_API_KEY",
origin: "YOUR_ORIGIN_ADDRESS",
destination: "YOUR_DESTINATION_ADDRESS",
mode: "transit",
interval: 60000, // 1 minute
showTransitDetails: true, // Set to true to display step-by-step transit details
customLabel: "Estimated Time to Get to Work", // Custom label for the module
debounceDelay: 10000, // 10 seconds by default, adjust as needed
},
// Initialize the module.
start: function () {
console.log("[MMM-MyTransitTime] Starting module: " + this.name);
this.transitTime = null;
// Define a function to fetch transit data with debouncing
this.fetchTransitData = this.debounce(this.fetchTransitData, this.config.debounceDelay);
// Schedule the first update.
this.scheduleUpdate();
},
// Override dom generator.
getDom: function () {
const wrapper = document.createElement("div");
wrapper.className = "my-transit-time";
if (this.transitTime) {
const timeElement = document.createElement("div");
timeElement.className = "transit-time right-aligned"; // Add a class for right alignment
timeElement.textContent = `Transit Time: ${this.transitTime}`;
wrapper.appendChild(timeElement);
if (this.config.showTransitDetails && this.transitDetails) {
const detailsList = document.createElement("ul");
detailsList.className = "transit-details";
this.transitDetails.forEach((detail) => {
const listItem = document.createElement("li");
const textSpan = document.createElement("span");
if (detail.includes("WALKING")) {
const walkingIcon = document.createElement("i");
walkingIcon.className = "fas fa-walking"; // FontAwesome walking icon
listItem.appendChild(walkingIcon);
textSpan.textContent = detail;
} else if (detail.includes("TRANSIT")) {
const transitIcon = document.createElement("i");
transitIcon.className = "fas fa-subway"; // FontAwesome subway/train icon
listItem.appendChild(transitIcon);
// Extract the line name from the detail and append it
const lineName = detail.match(/Take (.*?) from/)[1]; // Adjust regex if needed
textSpan.textContent = `${lineName} - ${detail}`;
}
listItem.appendChild(textSpan);
detailsList.appendChild(listItem);
});
wrapper.appendChild(detailsList);
}
} else {
const errorMessage = document.createElement("div");
errorMessage.className = "error-message";
errorMessage.textContent = "No transit data available.";
wrapper.appendChild(errorMessage);
}
return wrapper;
},
// Helper function to extract Google transit icon from detail
getGoogleTransitIcon: function (detail) {
const icon = detail.match(/icon:(.*?),/);
if (icon) {
return icon[1].trim();
}
return "";
},
// Override notification handler.
notificationReceived: function (notification, payload, sender) {
if (notification === "DOM_OBJECTS_CREATED") {
console.log("[MMM-MyTransitTime] DOM objects are ready, triggering the first update.");
// DOM objects are ready, trigger the first update.
this.sendSocketNotification("GET_TRANSIT_TIME", this.config);
}
},
// Override socket notification handler.
socketNotificationReceived: function (notification, payload) {
if (notification === "TRANSIT_TIME_RESULT") {
console.log("[MMM-MyTransitTime] Received TRANSIT_TIME_RESULT notification.");
this.transitTime = payload.transitTime;
this.transitDetails = payload.transitDetails;
this.updateDom();
// Schedule the next update.
this.scheduleUpdate();
}
},
// Schedule the next update.
scheduleUpdate: function () {
var self = this;
setInterval(function () {
console.log("[MMM-MyTransitTime] Scheduling the next update.");
// Call the debounced function to fetch transit data
self.fetchTransitData();
}, this.config.interval);
},
// Fetch transit data from the Google API.
fetchTransitData: function () {
const { apiKey, origin, destination, mode } = this.config;
const apiUrl = `https://maps.googleapis.com/maps/api/directions/json?origin=${encodeURIComponent(origin)}&destination=${encodeURIComponent(destination)}&mode=${mode}&transit_mode=subway&key=${apiKey}`;
// Make an HTTP request to the API
fetch(apiUrl)
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
})
.then((data) => {
// Process the API response and extract transit information
const transitTime = data.routes[0].legs[0].duration.text;
const transitSteps = data.routes[0].legs[0].steps.map((step) => {
if (step.travel_mode === "WALKING") {
return `${step.travel_mode}: Walk for ${step.distance.text} (${step.duration.text})`;
} else if (step.travel_mode === "TRANSIT") {
return `${step.travel_mode}: Take ${step.transit_details.line.name} from ${step.transit_details.departure_stop.name} to ${step.transit_details.arrival_stop.name} (${step.distance.text}, ${step.duration.text})`;
}
});
// Send the transit information to the front-end
this.sendSocketNotification("TRANSIT_TIME_RESULT", {
transitTime: transitTime,
transitDetails: transitSteps,
});
})
.catch((error) => {
console.error("[MMM-MyTransitTime] Error fetching transit data:", error);
});
},
// Debounce function to limit the rate of API requests.
debounce: function (func, delay) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
func.apply(context, args);
}, delay);
};
},
});