Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compact View #21

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/example4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions MMM-WienerLinien.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
margin-right: 5px;
}

.MMM-WienerLinien .heading {
font-size: 22px;
padding-top: 8px;
}

.MMM-WienerLinien .centered {
text-align: center;
}
Expand Down
173 changes: 146 additions & 27 deletions MMM-WienerLinien.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/**
* @file MMM-WienerLinien.js
*
Expand Down Expand Up @@ -43,29 +42,39 @@ Module.register('MMM-WienerLinien', {
ptBusNight: 'fa-bus',
ptTram: 'fa-train',
ptTramWLB: 'fa-train',
ptMetro: 'fa-subway'
ptMetro: 'fa-subway',
},

/**
* @member {Object} defaults - Defines the default config values.
* @property {string} view - Change the view between 'classic' and 'compact'.
* @property {string[]} lines - Favorite lines to display. Leave empty to display all.
* @property {string} header - Header that is shown on top of the module. Leave blank to hide.
* @property {string} displayIcons - Show or hide the icons of the table.
* @property {int} max - Amount of departure times to display.
* @property {boolean|number} shortenStation - Maximum characters for station name.
* @property {boolean|number} shortenDestination - Maximum characters for destination name.
* @property {int} rotateInterval - Speed of rotation.
* @property {int} updateInterval - Speed of update.
* @property {int} rotateInterval - Interval of rotation in ms.
* @property {int} updateInterval - Interval of update in ms.
* @property {int} animationSpeed - Speed of the template animation in ms.
* @property {string[]} elevatorStations - Station IDs that should be checked for elevator incidents.
* @property {string[]} incidentLines - Lines that should be checked for incidents.
* @property {boolean} incidentShort - Short or long incident description.
*/
defaults: {
view: 'classic',
lines: [],
header: 'WienerLinien',
displayIcons: true,
max: 5,
shortenStation: false,
shortenDestination: false,
rotateInterval: 20 * 1000,
updateInterval: 5 * 60 * 1000,
animationSpeed: 300,
elevatorStations: [],
incidentLines: [],
incidentShort: false
incidentShort: false,
},

/**
Expand All @@ -78,7 +87,7 @@ Module.register('MMM-WienerLinien', {
getTranslations() {
return {
en: 'translations/en.json',
de: 'translations/de.json'
de: 'translations/de.json',
};
},

Expand Down Expand Up @@ -127,6 +136,20 @@ Module.register('MMM-WienerLinien', {
return {};
}

if (this.config.view === 'compact') {
return this.getCompactView();
}

return this.getClassicView();
},

/**
* @function getClassicView
* @description Get all relevant data for template in classic view mode.
*
* @returns {object} Transformed data object for the classic view.
*/
getClassicView() {
const keys = Object.keys(this.stations);
this.maxIndex = keys.length;
if (this.index >= this.maxIndex) {
Expand All @@ -135,17 +158,86 @@ Module.register('MMM-WienerLinien', {

const station = this.stations[keys[this.index]];
const { name, departures: allDepartures } = station;
const departures = allDepartures.slice(0, Math.min(allDepartures.length, this.config.max));
const { lines, max } = this.config;

const departures = allDepartures
.filter(dep => lines.length === 0 || lines.includes(dep.line))
.slice(0, Math.min(allDepartures.length, max));

return {
departures,
name,
config: this.config,
elevators: this.elevators,
incidents: this.incidents
incidents: this.incidents,
};
},

/**
* @function getCompactView
* @description Get all relevant data for template in compact view mode.
*
* @returns {object} Transformed data object for the compact view.
*/
getCompactView() {
const stationData = [];

Object.values(this.stations).forEach(station => {
const { name, departures: allDepartures } = station;
const transformed = this.transformDepartures(allDepartures);
stationData.push({ name, departures: transformed });
});

return {
stationData,
config: this.config,
elevators: this.elevators,
incidents: this.incidents,
};
},

/**
* @function transformDepartures
* @description Transform the departures object for the compact view.
*
* @param {object} allDepartures - Object of all departures
* @returns {object} Array of transformed departures.
*/
transformDepartures(allDepartures) {
const newData = new Map();
const { lines, max } = this.config;

// Filter and accumulate data into the map
for (const dep of allDepartures) {
if (lines.length === 0 || lines.includes(dep.line)) {
const key = JSON.stringify({
towards: dep.towards,
line: dep.line,
type: dep.type,
});
if (!newData.has(key)) {
newData.set(key, []);
}
newData.get(key).push(dep.time);
}
}

// Transform map entries into the final array format
const transformed = [];
for (const [key, times] of newData.entries()) {
transformed.push({
...JSON.parse(key),
time: times.slice(0, max),
});
}

return transformed.sort(
(a, b) =>
a.line.localeCompare(b.line)
|| a.towards.localeCompare(b.towards)
);
},

/**
* @function start
* @description Sets nunjuck filters and starts station rotation interval.
Expand All @@ -157,14 +249,16 @@ Module.register('MMM-WienerLinien', {
Log.info(`Starting module: ${this.name}`);
moment.locale(config.language);

this.maxIndex = this.config.stations.length;
setInterval(() => {
this.updateDom(300);
this.index += 1;
if (this.index >= this.maxIndex) {
this.index = 0;
}
}, this.config.rotateInterval);
if (this.config.view === 'classic') {
this.maxIndex = this.config.stations.length;
setInterval(() => {
this.updateDom(this.config.animationSpeed);
this.index += 1;
if (this.index >= this.maxIndex) {
this.index = 0;
}
}, this.config.rotateInterval);
}

this.sendSocketNotification('CONFIG', this.config);

Expand All @@ -187,7 +281,7 @@ Module.register('MMM-WienerLinien', {
} else if (notification === 'INCIDENTS') {
this.incidents = payload;
}
this.updateDom(300);
this.updateDom(this.config.animationSpeed);
},

/**
Expand All @@ -197,18 +291,43 @@ Module.register('MMM-WienerLinien', {
* @returns {void}
*/
addFilters() {
this.nunjucksEnvironment().addFilter('timeUntil', time => moment().to(time));
this.nunjucksEnvironment().addFilter('timeUntil', time =>
moment().to(time)
);

this.nunjucksEnvironment().addFilter('icon', type => this.types[type] || 'fa-question');
this.nunjucksEnvironment().addFilter(
'timeShort',
time => moment(time).diff(moment(), 'minutes') + "'"
);

this.nunjucksEnvironment().addFilter('isEmpty', array => !array || array.length < 1);
this.nunjucksEnvironment().addFilter('titlecase', text =>
text.replace(
/\w\S*/g,
text =>
text.charAt(0).toUpperCase()
+ text.substring(1).toLowerCase()
)
);

this.nunjucksEnvironment().addFilter('shortenText', (text, maxLength) => {
if (!maxLength || text.length < maxLength) {
return text;
}
this.nunjucksEnvironment().addFilter(
'icon',
type => this.types[type] || 'fa-question'
);

return `${text.slice(0, maxLength)}&#8230;`;
});
}
this.nunjucksEnvironment().addFilter(
'isEmpty',
array => !array || array.length < 1
);

this.nunjucksEnvironment().addFilter(
'shortenText',
(text, maxLength) => {
if (!maxLength || text.length < maxLength) {
return text;
}

return `${text.slice(0, maxLength)}&#8230;`;
}
);
},
});
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,25 @@

Public Transport of Vienna/Austria Module for MagicMirror²

## Example
## Examples

![Station 1](.github/example.jpg) ![Station 2](.github/example2.jpg) ![Incidents](.github/example3.PNG)
### Classic View

Periodically rotates between different stations.

![Station 1](.github/example.jpg) ![Station 2](.github/example2.jpg)

### Compact View

Shows all stations in one view without rotating.

![CompactView](.github/example4.png)

### Incidents

Shows incident data (classic view only).

![Incidents](.github/example3.png)

## Dependencies

Expand Down Expand Up @@ -38,11 +54,16 @@ Public Transport of Vienna/Austria Module for MagicMirror²
| **Option** | **Default** | **Description** |
| --- | --- | --- |
| `stations` | REQUIRED | Insert here the station ids you want to display data from [How to find an ID?](https://till.mabe.at/rbl/). |
| `view` | `classic` | Switch between `classic` and `compact` view. (See examples) |
| `lines` | [] | Set a filter to only show your favorite lines (e.g. `["U4", "U1"]`). Leave empty to show all. |
| `header` | `WienerLinien` | Set the header above the module. Leave empty to hide the header. |
| `displayIcons` | `true` | Display or hide the icons above the table. |
| `max` | `5` | How many departures should be displayed. |
| `shortenStation` | `false` | After how many characters the station name should be cut. Default: show full name. |
| `shortenDestination` | `false` | After how many characters the destination name should be cut. Default: show full name. |
| `rotateInterval` | `20000` (20 sec) | How fast should be switched between the stations. |
| `updateInterval` | `300000` (5 mins) | How often should the data be fetched. |
| `animationSpeed` | `300` (300 ms) | How fast should the animation on data changes run. |
| `elevatorStations` | EMPTY | Insert the station ids where you would like to know elevator disruptions. |
| `incidentLines` | EMPTY | Insert the line names for which you would like to know disruptions. |
| `incidentShort` | `false` | If true, also the changes to lines are displayed (AZBLinienspezialtext [see documentation](https://data.wien.gv.at/pdf/wienerlinien-echtzeitdaten-dokumentation.pdf)), otherwise only current disruptions. |
6 changes: 3 additions & 3 deletions node_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ module.exports = NodeHelper.create({
description,
lines: _.join(relatedLines, ', ')
}));
const sortedIncidents = _.sortBy(mappedElevators, 'lines');
const sortedIncidents = _.sortBy(mappedIncidents, 'lines');

this.sendSocketNotification('INCIDENTS', sortedIncidents);
},
Expand All @@ -190,7 +190,7 @@ module.exports = NodeHelper.create({
stations[stationName] = { name: _.get(entry, 'locationStop.properties.title'), departures: [] };
}

for (const {departures, name, towards, type} of entry.lines) {
for (const { departures, name, towards, type } of entry.lines) {
let metroFlag = false;

for (const departure of departures.departure) {
Expand All @@ -201,7 +201,7 @@ module.exports = NodeHelper.create({

const departureTimeProp = _.has(departure.departureTime, 'timeReal') ? 'timeReal' : 'timePlanned';

stations[stationName].departures.push({time: departure.departureTime[departureTimeProp], towards, line: name, type});
stations[stationName].departures.push({ time: departure.departureTime[departureTimeProp], towards, line: name, type });
}

if (metroFlag) {
Expand Down
Loading