Persist devices state across restarts. #249

This commit is contained in:
Koenkk
2018-08-13 19:21:55 +02:00
parent 5e96c46a7a
commit 04b2f24d6b
3 changed files with 68 additions and 7 deletions
+2 -1
View File
@@ -60,4 +60,5 @@ typings/
# data
data/database.db
data/config.json
data/log*.txt
data/log*.txt
data/state.json
+11 -6
View File
@@ -1,5 +1,6 @@
const MQTT = require('./mqtt');
const Zigbee = require('./zigbee');
const State = require('./state');
const logger = require('./util/logger');
const settings = require('./util/settings');
const zigbeeShepherdConverters = require('zigbee-shepherd-converters');
@@ -32,7 +33,7 @@ class Controller {
constructor() {
this.zigbee = new Zigbee();
this.mqtt = new MQTT();
this.stateCache = {};
this.state = new State();
this.configured = [];
this.handleZigbeeMessage = this.handleZigbeeMessage.bind(this);
this.handleMQTTMessage = this.handleMQTTMessage.bind(this);
@@ -99,8 +100,8 @@ class Controller {
sendAllCachedStates() {
this.zigbee.getAllClients().forEach((device) => {
if (this.stateCache.hasOwnProperty(device.ieeeAddr)) {
this.mqttPublishDeviceState(device.ieeeAddr, this.stateCache[device.ieeeAddr], false);
if (this.state.exists(device.ieeeAddr)) {
this.mqttPublishDeviceState(device.ieeeAddr, this.state.get(device.ieeeAddr), false);
}
});
}
@@ -152,6 +153,7 @@ class Controller {
}
stop(callback) {
this.state.save();
this.mqtt.disconnect();
this.pollTimer(false);
this.softResetTimeout(false);
@@ -393,6 +395,9 @@ class Controller {
// Remove from configuration.yaml
settings.removeDevice(deviceID);
// Remove from state
this.state.remove(deviceID);
logger.info(`Successfully removed ${deviceID}`);
this.mqtt.log('device_removed', message);
};
@@ -549,13 +554,13 @@ class Controller {
mqttPublishDeviceState(deviceID, payload, cache) {
if (cacheState) {
// Add cached state to payload
if (this.stateCache[deviceID]) {
payload = objectAssignDeep.noMutate(this.stateCache[deviceID], payload);
if (this.state.exists(deviceID)) {
payload = objectAssignDeep.noMutate(this.state.get(deviceID), payload);
}
// Update state cache with new state.
if (cache) {
this.stateCache[deviceID] = payload;
this.state.set(deviceID, payload);
}
}
+55
View File
@@ -0,0 +1,55 @@
const logger = require('./util/logger');
const data = require('./util/data');
const fs = require('fs');
const saveInterval = 1000 * 60 * 5; // 5 minutes
class State {
constructor() {
this.state = {};
this.file = data.joinPath('state.json');
this._load();
// Save the state on every interval
this.timer = setInterval(() => this.save(), saveInterval);
}
_load() {
if (fs.existsSync(this.file)) {
try {
this.state = JSON.parse(fs.readFileSync(this.file, 'utf8'));
logger.debug(`Loaded state from file ${this.file}`);
} catch (e) {
logger.debug(`Failed to load state from file ${this.file} (corrupt file?)`);
}
} else {
logger.debug(`Can't load state from file ${this.file} (doesn't exsist)`);
}
}
save() {
logger.debug(`Saving state to file ${this.file}`);
const json = JSON.stringify(this.state, null, 4);
fs.writeFileSync(this.file, json, 'utf8');
}
exists(ID) {
return this.state.hasOwnProperty(ID);
}
get(ID) {
return this.state[ID];
}
set(ID, state) {
this.state[ID] = state;
}
remove(ID) {
if (this.exists(ID)) {
delete this.state[ID];
}
}
}
module.exports = State;