Files
mmm-myq/MMM-MyQ.js
Parnic 69b37c8552 Switch to a working MyQ API library
The myq-api lib I was using is still not updated to the new API, and as
a result doesn't work. This lib is recent and seems to be powering an
active project.

I'm sure this isn't exactly how it needs to be done long-term, but this
gets things functional for me right now and I can iterate on it as I go.
2021-09-21 22:53:28 -05:00

143 lines
4.2 KiB
JavaScript

/* Magic Mirror
* Module: MMM-MyQ
*
* By parnic https://github.com/parnic/MMM-MyQ
* MIT Licensed.
*/
Module.register('MMM-MyQ', {
defaults: {
email: '',
password: '',
types: ['wifigaragedooropener'],
columns: 1,
updateInterval: 5 * 60 * 1000 // every 5 minutes
},
states: {
closed: 'closed',
open: 'open',
closing: 'closing',
opening: 'opening'
},
getStyles() {
return ['MMM-MyQ.css'];
},
start() {
Log.info(`Starting module: ${this.name}`);
this.devices = [];
this.sendSocketNotification('MYQ_CONFIG', this.config);
},
socketNotificationReceived(notification, payload) {
if (notification === 'MYQ_LOGGED_IN') {
this.actions = payload;
} else if (notification === 'MYQ_ERROR') {
const {context, err} = payload;
Log.error(`context=${context}, err=${err.message}`);
} else if (notification === 'MYQ_TOGGLE_COMPLETE') {
this.scheduleUpdate();
} else if (notification === 'MYQ_DEVICES_FOUND') {
payload.forEach((entry) => {
let existingDevice = this.getDeviceBySerial(entry.serial_number);
if (!existingDevice) {
this.devices.push(entry);
existingDevice = entry;
} else {
existingDevice.state = entry.state;
}
if (existingDevice.desiredState) {
if (existingDevice.state.door_state !== existingDevice.desiredState) {
this.scheduleUpdate();
} else {
existingDevice.desiredState = null;
}
}
});
this.updateDom();
}
},
scheduleUpdate() {
if (!this.timeout) {
this.timeout = setTimeout(() => {
this.timeout = null;
this.sendSocketNotification('MYQ_UPDATE');
}, 5000);
}
},
getDom() {
const wrapper = document.createElement('div');
let table = document.createElement('table');
wrapper.appendChild(table);
let cols = -1;
let row;
this.devices.forEach((device) => {
cols++;
if (cols % this.config.columns === 0) {
row = document.createElement('tr');
table.appendChild(row);
}
let cell = document.createElement('td');
cell.classList.add('btn');
cell.appendChild(this.getDeviceDom(device));
row.appendChild(cell);
});
return wrapper;
},
getDeviceDom(device) {
const nameLabel = document.createElement('div');
nameLabel.textContent = device.name;
const btn = document.createElement('button');
btn.appendChild(nameLabel);
if (device.desiredState) {
btn.disabled = true;
} else {
const actionLabel = document.createElement('div');
let action = this.actions.close;
actionLabel.textContent = this.translate('Opened');
if (device.state.door_state === this.states.closed) {
action = this.actions.open;
actionLabel.textContent = this.translate('Closed');
}
btn.dataset['action'] = action;
btn.appendChild(actionLabel);
}
btn.dataset['serial_number'] = device.serial_number;
btn.classList.add('control', 'light');
btn.addEventListener('click', (evt) => { this.deviceBtnAction(btn); });
return btn;
},
deviceBtnAction(btn) {
let device = this.getDeviceBySerial(btn.dataset['serial_number']);
let action = btn.dataset['action'];
if (device && action) {
device.desiredState = action === this.actions.close ? this.states.closed : this.states.open;
this.sendSocketNotification('MYQ_TOGGLE', {device, action});
this.updateDom();
}
},
getDeviceBySerial(serialNumber) {
return this.devices.find((device) => device.serial_number === serialNumber);
}
});