UNPKG

iobroker.go-e

Version:

go-e ist die Aufforderung, sich elektrisch zu bewegen. e-Mobilität ist unser Antrieb, wobei unsere Kernkompetenz die Ladetechnik für Elektroautos ist. Von der einzelnen Ladestation für e-Autos über Photovoltaik-Anbindung bis hin zum Lastmanagement von gan

827 lines (797 loc) 81.6 kB
'use strict'; /* * Created with @iobroker/create-adapter v1.26.0 */ // The adapter-core module gives you access to the core ioBroker functions // you need to create an adapter const utils = require('@iobroker/adapter-core'); // Load your modules here, e.g.: // const fs = require("fs"); const axios = require('axios').default; const {default: PQueue} = require('p-queue'); const schema = require('./lib/schema.js').schema; class GoE extends utils.Adapter { /** * @param {Partial<utils.AdapterOptions>} [options={}] */ constructor(options) { super({ ...options, name: 'go-e', }); this.on('ready', this.onReady.bind(this)); this.on('stateChange', this.onStateChange.bind(this)); // this.on("objectChange", this.onObjectChange.bind(this)); // this.on("message", this.onMessage.bind(this)); this.on('unload', this.onUnload.bind(this)); // Timer Object for the update interval for ampere to the adapter this.ampTimer = null; // Timestamp for lastSwitchRequest this.lastPhaseSwitchRequest = null; // Timestamp for lastStop Request this.lastStopRequest = null; // Translation Object this.translationObject = { al1: 'settings.ampere_level1', al2: 'settings.ampere_level2', al3: 'settings.ampere_level3', al4: 'settings.ampere_level4', al5: 'settings.ampere_level5', lbr: 'settings.color.led_brightness' }; // Translation Object API v2 this.translationObjectV2 = { alw: {name: 'allow_charging'}, rbc: {name: 'reboot_counter'}, rbt: {name: 'reboot_timer'}, car: {name: 'car'}, amp: {name: 'ampere'} }; // Ack alignment object this.ackObj = {}; } /** * Is called when databases are connected and adapter received configuration. */ async onReady() { // Initialize your adapter here // Write it to possible values this.log.info('Adapter is staring in Version setByGitHubActions'); // this.log.debug('Update selectable values from ' + JSON.stringify(this.config.selectedAttributes) + ' to ' + Object.keys(this.translationObjectV2) + '; Working with Version ' + this.config.apiVersion); // this.config.possibleAttributes = Object.keys(this.translationObjectV2); // The adapters config (in the instance object everything under the attribute "native") is accessible via // this.config: this.log.info('Server: ' + this.config.serverName); this.log.info('Intervall: ' + this.config.serverInterval); this.log.info('Calculation Method: ' + this.config.calcMethod); // In order to get state updates, you need to subscribe to them. The following line adds a subscription for our variable we have created above. this.subscribeStates('access_state'); this.subscribeStates('allow_charging'); this.subscribeStates('ampere'); this.subscribeStates('amperePV'); this.subscribeStates('energy.adjustAmpLevelInWatts'); this.subscribeStates('energy.max_watts'); this.subscribeStates('max_load'); this.subscribeStates('settings.ampere_level1'); this.subscribeStates('settings.ampere_level2'); this.subscribeStates('settings.ampere_level3'); this.subscribeStates('settings.ampere_level4'); this.subscribeStates('settings.ampere_level5'); this.subscribeStates('settings.color.idle'); this.subscribeStates('settings.color.charging'); this.subscribeStates('settings.color.finish'); this.subscribeStates('settings.led_save_energy'); this.subscribeStates('settings.led_brightness'); this.subscribeStates('solarLoadOnly'); this.subscribeStates('stop_state'); this.subscribeStates('unlock_state'); this.subscribeStates('phaseSwitchMode'); this.subscribeStates('schedule.allowChargeingForMins'); this.subscribeStates('schedule.stopChargeingAt'); if(this.config.calcMethod == 'iob') { // Disable FUP (Solar überschuss) if(this.config.apiVersion == 2) this.setValueV2('fup', false).catch(() => { // Do nothing }); // get updates from a foreign adapter if it is set in Settings if(this.config.houseBatteryForeignObjectID) { this.subscribeForeignStates(this.config.houseBatteryForeignObjectID); this.ackObj[this.config.houseBatteryForeignObjectID] = this.config.houseBatteryForeignObjectAck; this.log.debug('Subscribe foreign object ' + this.config.houseBatteryForeignObjectID); } if(this.config.houseConsumptionForeignObjectID) { this.subscribeForeignStates(this.config.houseConsumptionForeignObjectID); this.ackObj[this.config.houseConsumptionForeignObjectID] = this.config.houseConsumptionForeignObjectAck; this.log.debug('Subscribe foreign object ' + this.config.houseConsumptionForeignObjectID); } if(this.config.solarPowerForeignObjectID) { this.subscribeForeignStates(this.config.solarPowerForeignObjectID); this.ackObj[this.config.solarPowerForeignObjectID] = this.config.solarPowerForeignObjectAck; this.log.debug('Subscribe foreign object ' + this.config.solarPowerForeignObjectID); } } this.log.silly('Ack-Obj: ' + JSON.stringify(this.ackObj)); // setup axios axios.defaults.baseURL = 'http://' + this.config.serverName; // Get all Information for the first time. await this.getStateFromDevice(); // Start the Adapter to sync in the interval this.interval = setInterval(async () => { await this.getStateFromDevice(); }, this.config.serverInterval * 1000); if(this.config.calcMethod !== 'iob' && this.config.apiVersion == 2) { // Start the Adapter to sync in the interval this.interval = setInterval(async () => { await this.writeIds(); }, 4 * 1000); } else if (this.config.calcMethod !== 'iob' && this.config.apiVersion != 2) { this.log.error('For Hardware use to calc PV is API V2 required. But is not enabled in settings.'); } } /** * Is called when adapter shuts down - callback has to be called under any circumstances! * @param {() => void} callback */ onUnload(callback) { try { // Here you must clear all timeouts or intervals that may still be active // clearTimeout(timeout1); // clearTimeout(timeout2); // ... // clearInterval(interval1); // @ts-ignore clearInterval(this.interval); callback(); } catch (e) { callback(); this.log.silly('callback ' + e); } } // If you need to react to object changes, uncomment the following block and the corresponding line in the constructor. // You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`. // /** // * Is called if a subscribed object changes // * @param {string} id // * @param {ioBroker.Object | null | undefined} obj // */ // onObjectChange(id, obj) { // if (obj) { // // The object was changed // this.log.info(`object ${id} changed: ${JSON.stringify(obj)}`); // } else { // // The object was deleted // this.log.info(`object ${id} deleted`); // } // } /** * Is called if a subscribed state changes * @param {string} id * @param {ioBroker.State | null | undefined} state */ onStateChange(id, state) { if (state) { // The state was changed if (!state.ack) { // If it is already acknoladged, we dont have to send it to the go-eCharger device. Or have to handle the change. this.log.silly(`state ${id} changed: ${state.val} (ack = ${state.ack}) namespace: ` + this.namespace); // Handle null values with the rejection if(state.val === null) { this.log.warn('Not able to handle null Values in ' + id); return; } switch (id) { // Sort by alphabet of attribute case this.namespace + '.access_state': if(parseInt(state.val.toString()) == 0 || parseInt(state.val.toString(), 10) == 1 || parseInt(state.val.toString(), 10) == 2 ) { this.setValue('ast', parseInt(state.val.toString(), 10)); } else { this.log.warn('Could not set value ' + state.val.toString() + ' in ' + id); } break; case this.namespace + '.allow_charging': if(parseInt(state.val.toString()) == 0 || parseInt(state.val.toString(), 10) == 1 ) { this.setValue('alw', parseInt(state.val.toString(), 10)); } else { this.log.warn('Could not set value ' + state.val.toString() + ' in ' + id); } break; case this.namespace + '.ampere': this.setValue('amp', state.val.toString()); break; case this.namespace + '.amperePV': this.setValue('amx', state.val.toString()); break; case this.namespace + '.energy.adjustAmpLevelInWatts': this.adjustAmpLevelInWatts(parseInt(state.val.toString(), 10)); this.setState('energy.adjustAmpLevelInWatts', { val: parseInt(state.val.toString(), 10), ack: true }); break; case this.namespace + '.energy.max_watts': this.updateAmpLevel(parseInt(state.val.toString())); this.setState('energy.max_watts', { val: parseInt(state.val.toString(), 10), ack: true }); break; case this.namespace + '.max_load': this.setValue('dwo', parseInt(state.val.toString(), 10) * 10); break; case this.namespace + '.settings.ampere_level1': this.setAmpLevelToButton('al1', parseInt(state.val.toString(), 10)); break; case this.namespace + '.settings.ampere_level2': this.setAmpLevelToButton('al2', parseInt(state.val.toString(), 10)); break; case this.namespace + '.settings.ampere_level3': this.setAmpLevelToButton('al3', parseInt(state.val.toString(), 10)); break; case this.namespace + '.settings.ampere_level4': this.setAmpLevelToButton('al4', parseInt(state.val.toString(), 10)); break; case this.namespace + '.settings.ampere_level5': this.setAmpLevelToButton('al5', parseInt(state.val.toString(), 10)); break; case this.namespace + '.settings.color.idle': // @ts-ignore // Check off null is done this.setValue('cid', /^#?([a-f\d]{6})$/i.exec(state.val.toString()) !== null ? parseInt(/^#?([a-f\d]{6})$/i.exec(state.val.toString())[1], 16) : 0); break; case this.namespace + '.settings.color.charging': // @ts-ignore // Check off null is done // this.setValue("cch", /^#?([a-f\d]{6})$/i.exec(state.val.toString()) !== null ? parseInt(/^#?([a-f\d]{6})$/i.exec(state.val.toString())[1], 16) : 0); // bug in versions starting 042; have to use V2 this.setValueV2('cch', encodeURIComponent(/^#?([a-f\d]{6})$/i.exec(state.val.toString()) !== null ? state.val.toString() : '#FFFFFF')).catch(); break; case this.namespace + '.settings.color.finish': // @ts-ignore // Check off null is done this.setValue('cfi', /^#?([a-f\d]{6})$/i.exec(state.val.toString()) !== null ? parseInt(/^#?([a-f\d]{6})$/i.exec(state.val.toString())[1], 16) : 0); break; case this.namespace + '.settings.color.led_save_energy': this.setValue('lse', parseInt(state.val.toString(), 10)); break; case this.namespace + '.settings.color.led_brightness': this.setValue('lbr', parseInt(state.val.toString(), 10)); break; case this.namespace + '.solarLoadOnly': if(this.config.calcMethod == 'iob') { // Is solarOnly => false (off) if(!state.val) { this.setValue('alw', 1); if(this.config.apiVersion == 2) { this.setValueV2('fup', 0).catch(() => {}); // go-e Solarladen deaktivieren this.setValueV2('psm', this.config.defaultPSM).catch(() => {}); // Phases Switch to auto } } else { this.setValueV2('psm', 1).catch(() => {}); // Phases Switch to 1-phase } } else { this.setValueV2('fup', state.val) .then(() => { this.setState('solarLoadOnly', {ack:true}); }) .catch(() => { // Do nothing }); } break; case this.namespace + '.stop_state': if(parseInt(state.val.toString()) === 0 || parseInt(state.val.toString()) == 2 ) { this.setValue('stp', parseInt(state.val.toString(), 10)); } else { this.log.warn('Could not set value ' + state.val.toString() + ' into ' + id); } break; case this.namespace + '.unlock_state': if(parseInt(state.val.toString()) === 0 || parseInt(state.val.toString()) === 1 || parseInt(state.val.toString()) == 2 ) { this.setValue('ust', parseInt(state.val.toString(), 10)); } else { this.log.warn('Could not set value ' + state.val.toString() + ' into ' + id); } break; case this.namespace + '.phaseSwitchMode': if(parseInt(state.val.toString()) === 0 || parseInt(state.val.toString()) === 1 || parseInt(state.val.toString()) == 2 ) { this.setValueV2('psm', parseInt(state.val.toString())).catch(() => {}); } else { this.log.warn('Could not set value ' + state.val.toString() + ' into ' + id + ' (psm)'); } break; case this.namespace + '.schedule.allowChargeingForMins': if(parseInt(state.val.toString()) > 0) { this.setState('schedule.allowChargeingForMins', {val: state.val, ack: true}); this.setState('schedule.stopChargeingAt', {val: new Date(Date.now() + (parseInt(state.val.toString()) * 60 * 1000)).toISOString(), ack: true}); this.setState('schedule.stopChargeingEnabled', {val: true, ack:true}); if(state.val !== undefined && state.val !== null) this.setStopTimeout = setTimeout(() => { this.setValue('alw', 0); this.log.info('Stop process because of schedule Minutes'); }, parseInt(state.val.toString()) * 1000); } break; case this.namespace + '.schedule.stopChargeingAt': if(!isNaN(Date.parse(state.val.toString())) && Date.parse(state.val.toString()) > Date.now()) { this.setState('schedule.stopChargeingAt', {val: state.val, ack: true}); this.setState('schedule.stopChargeingEnabled', {val: true, ack:true}); if(state.val !== undefined && state.val !== null) this.setStopTimeout = setTimeout(() => { this.setValue('alw', 0); this.log.info('Stop process because of schedule At'); }, Date.parse(state.val.toString()) - Date.now()); } break; case this.config.solarPowerForeignObjectID: case this.config.houseBatteryForeignObjectID: case this.config.houseConsumptionForeignObjectID: if(this.ackObj[id] === false) { this.log.silly('Will work on ' + id + ' becase ack is ' + state.ack + ' and should be ' + this.ackObj[id]); this.calculateFromForeignObjects(id); } else { this.log.silly('Will NOT work on ' + id + ' becase ack is ' + state.ack + ' and should be ' + this.ackObj[id]); } break; default: this.log.error('Not developed function to write ' + id + ' with state ' + state.val.toString()); } } else { // Ack = true switch (id) { case this.config.solarPowerForeignObjectID: case this.config.houseBatteryForeignObjectID: case this.config.houseConsumptionForeignObjectID: this.log.silly(`state ${id} changed: ${state.val} (ack = ${state.ack}) namespace: ` + this.namespace); if(this.ackObj[id] === true) { this.log.silly('Will work on ' + id + ' becase ack is ' + state.ack + ' and should be ' + this.ackObj[id]); this.calculateFromForeignObjects(id); } else { this.log.silly('Will NOT work on ' + id + ' becase ack is ' + state.ack + ' and should be ' + this.ackObj[id]); } break; } } } else { // The state was deleted this.log.info(`state ${id} deleted`); } } // If you need to accept messages in your adapter, uncomment the following block and the corresponding line in the constructor. // /** // * Some message was sent to this instance over message box. Used by email, pushover, text2speech, ... // * Using this method requires "common.message" property to be set to true in io-package.json // * @param {ioBroker.Message} obj // */ // onMessage(obj) { // if (typeof obj === "object" && obj.message) { // if (obj.command === "send") { // // e.g. send email or pushover or whatever // this.log.info("send command"); // // Send response in callback if required // if (obj.callback) this.sendTo(obj.from, obj.command, "Message received", obj.callback); // } // } // } /** * This function get the JSON Object from the go-E Charger status API */ async getStateFromDevice() { // let apiEndpoint = "/status"; if(this.config.apiVersion == 2) { // apiEndpoint = "/api/status?filter=" + Object.keys(this.translationObjectV2).join(","); // Get additional parameters from API v2 this.log.debug(`Starte V2 Abfrage an: http://${this.config.serverName}/api/status?filter=psm`); axios.get('/api/status?filter=psm') .then((o) => { this.log.silly('Response: ' + o.status + ' - ' + o.statusText + ' with data as ' + typeof o.data); // this.log.debug(JSON.stringify(o.data)); if(typeof o.data == 'object') { this.setState('phaseSwitchMode', { 'val': parseInt(o.data['psm']), ack: true }); } else { this.log.warn(`Response of psm is ${typeof o.data}`); } }) .catch((e) => { this.log.error(e); }); // Hole die benutzerdefinierten Informationen const queryStr = this.config.selectedAttributes.join(','); this.log.debug(`http://${this.config.serverName}/api/status?filter=${queryStr}`); // todo abfrage erstellen. axios.get(`/api/status?filter=${queryStr}`) .then((o) => { this.log.silly('Response: ' + o.status + ' - ' + o.statusText + ' with data as ' + typeof o.data); this.log.debug(JSON.stringify(o.data)); this.processStatusObject(o.data); }) .catch((e) => { this.log.error(e); }); } // Get all other attributes from API-V1 // this.log.debug("Starte V1 Abfrage an: http://" + this.config.serverName + apiEndpoint); axios.defaults.baseURL = 'http://' + this.config.serverName; await axios.get('/status') .then((o) => { this.log.silly('Response: ' + o.status + ' - ' + o.statusText + ' with data as ' + typeof o.data); this.log.debug(JSON.stringify(o.data)); if(typeof o.data != 'object') { this.log.error('Respose id type ' + (typeof o.data) + '; ' + JSON.stringify(o.data)); } else { const validation = schema.validate(o.data,{abortEarly: false}); // @ts-ignore if (validation.error != undefined && (validation.error || validation.value === undefined)) { if (validation.value === undefined) { this.log.error('API send no content'); } else { this.log.error('API response validation error: ' + JSON.stringify(validation.error.details)); this.log.info(JSON.stringify(validation.error._original)); } } else { this.processStatusObject(o.data); } } this.setState('info.connection', true, true); }) .catch(e => { if(e.code == 'ENOTFOUND') { this.setState('info.connection', false, true); this.log.warn('Host not found: ' + this.config.serverName); } else if(e.code == 'EAI_AGAIN') { this.setState('info.connection', false, true); this.log.warn('Network/DNS broken to: ' + this.config.serverName); } else if(e.code == 'ECONNRESET') { this.setState('info.connection', false, true); this.log.warn('Cant connect to host ' + this.config.serverName); } else if(e.code == 'EHOSTUNREACH') { this.setState('info.connection', false, true); this.log.warn('Can not route to the host ' + this.config.serverName); } else if (e.response && e.response.status === 404) { this.setState('info.connection', false, true); this.log.warn('Adapter not ready ' + this.config.serverName); } else { this.log.error(e.message); } }); } /** * This function is writing the IDS endpoint on the go-e adapter based to given attributes */ async writeIds() { let availWatts = await this.getNumberFromForeignObjectId(this.config.solarPowerForeignObjectID); let houseBattery = await this.getNumberFromForeignObjectId(this.config.houseBatteryForeignObjectID); if(this.config.solarPowerForeignObjectNegate) { availWatts = availWatts * -1; this.log.silly('Negate watts of Solar; new: ' + availWatts); } if(this.config.houseBatteryForeignObjectNegate) { houseBattery = houseBattery * -1; this.log.silly('Negate watts of HouseBattery; new: ' + houseBattery); } const buildObj = { pGrid: availWatts, pAkku: houseBattery }; axios.get('/api/set?ids=' + JSON.stringify(buildObj)) .then((res) => { this.log.debug('Wrote ids Object: ' + JSON.stringify(buildObj) + ' with response ' + JSON.stringify(res.data)); }) .catch((e) => { this.log.warn('Was not able to write ids: ' + JSON.stringify(buildObj) + '; Error: ' + e.message); }); } /** * Process a default status response as descibed in the api documentation of go-eCharger * @param {object} o */ async processStatusObject(o) { try { // Const for variable pha const postContactorPhase1 = 1; const postContactorPhase2 = 2; const postContactorPhase3 = 4; const preContactorPhase1 = 8; const preContactorPhase2 = 16; const preContactorPhase3 = 32; // Allows only 4 asnychronous calls others are queued const queue = new PQueue({concurrency: 4}); for (const [key, value] of Object.entries(o)) { //console.log(`${key}: ${value}`); switch (key) { case 'version': await queue.add(() => this.setState('encryption', { val: o.version == 'C' ? true : false, ack: true })); // read break; case 'tme': try { // TME provides 2208201643 // sometimes it provides "0302-300526" see #171 // TODO: No glue what this is about. // Realdate: 22th August 2020 at 16:43 (CET) // this.log.debug(" Synctime: " + o.tme); const reggie = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/; // @ts-ignore const [, day, month, year, hours, minutes] = reggie.exec(o.tme); const dateObject = new Date(parseInt(year, 10)+2000, parseInt(month, 10)-1, parseInt(day, 10), parseInt(hours, 10), parseInt(minutes, 10), 0); await queue.add(() => this.setState('synctime', { val: dateObject.toISOString(), ack: true })); } catch (e) { // @ts-ignore this.log.info('Cloud not store synctime, because of error ' + e.message); } break; case 'rbc': await queue.add(() => this.setState('reboot_counter', { val: parseInt(o.rbc, 10), ack: true })); // read, V1, V2 break; case 'car': await queue.add(() => this.setState('car', { val: parseInt(o.car, 10), ack: true })); // read, V1, V2 break; case 'rbt': await queue.add(() => this.setState('reboot_timer', { val: parseInt(o.rbt, 10), ack: true })); // read, V1, V2 break; case 'amp': await queue.add(() => this.setState('ampere', { val: parseInt(o.amp, 10), ack: true })); // write, V1, V2 break; case 'amx': if(o.amx === undefined || o.amx == null) { await queue.add(() => this.setState('amperePV', { val: parseInt(o.amp, 10), ack: true })); // COPY AMP Value to AMX V1 } else { await queue.add(() => this.setState('amperePV', { val: parseInt(o.amx, 10), ack: true })); // write, V1 } break; case 'err': await queue.add(() => this.setState('error', { val: parseInt(o.err, 10), ack: true })); // read break; case 'ast': await queue.add(() => this.setState('access_state', { val: parseInt(o.ast, 10), ack: true })); // write break; case 'alw': if(typeof o.alw == 'boolean') await queue.add(() => this.setState('allow_charging', { val: + o.alw, ack: true })); // V2 (Convert to Integer by using +) else await queue.add(() => this.setState('allow_charging', { val: parseInt(o.alw, 10), ack: true })); // write, V2 break; case 'stp': await queue.add(() => this.setState('stop_state', { val: parseInt(o.stp, 10), ack: true })); // write break; case 'pha': await queue.add(() => this.setState('phases', { val: parseInt(o.pha, 10), ack: true })); // read // Split phases in single states await queue.add(() => this.setState('energy.phase1.preContactorActive', { val: ((parseInt(o.pha, 10) & preContactorPhase1) == preContactorPhase1), ack: true})); //read await queue.add(() => this.setState('energy.phase1.postContactorActive', { val: ((parseInt(o.pha, 10) & postContactorPhase1) == postContactorPhase1), ack: true})); //read await queue.add(() => this.setState('energy.phase2.preContactorActive', { val: ((parseInt(o.pha, 10) & preContactorPhase2) == preContactorPhase2), ack: true})); //read await queue.add(() => this.setState('energy.phase2.postContactorActive', { val: ((parseInt(o.pha, 10) & postContactorPhase2) == postContactorPhase2), ack: true})); //read await queue.add(() => this.setState('energy.phase3.preContactorActive', { val: ((parseInt(o.pha, 10) & preContactorPhase3) == preContactorPhase3), ack: true})); //read await queue.add(() => this.setState('energy.phase3.postContactorActive', { val: ((parseInt(o.pha, 10) & postContactorPhase3) == postContactorPhase3), ack: true})); //read await queue.add(() => this.setState('energy.phase1.voltage', { val: parseInt(o.nrg[0], 10), ack: true })); // read break; case 'nrg': await queue.add(() => this.setState('energy.phase2.voltage', { val: parseInt(o.nrg[1], 10), ack: true })); // read await queue.add(() => this.setState('energy.phase3.voltage', { val: parseInt(o.nrg[2], 10), ack: true })); // read await queue.add(() => this.setState('energy.neutral.voltage', { val: parseInt(o.nrg[3], 10), ack: true })); // read await queue.add(() => this.setState('energy.phase1.ampere', { val: (o.nrg[4] / 10), ack: true })); // read await queue.add(() => this.setState('energy.phase2.ampere', { val: (o.nrg[5] / 10), ack: true })); // read await queue.add(() => this.setState('energy.phase3.ampere', { val: (o.nrg[6] / 10), ack: true })); // read await queue.add(() => this.setState('energy.phase1.power', { val: (o.nrg[7] / 10), ack: true })); // read await queue.add(() => this.setState('energy.phase2.power', { val: (o.nrg[8] / 10), ack: true })); // read await queue.add(() => this.setState('energy.phase3.power', { val: (o.nrg[9] / 10), ack: true })); // read await queue.add(() => this.setState('energy.neutral.power', { val: (o.nrg[10] / 10), ack: true })); // read await queue.add(() => this.setState('energy.power', { val: (o.nrg[11] / 100), ack: true })); // read await queue.add(() => this.setState('energy.phase1.power_coefficient', { val: parseInt(o.nrg[12], 10), ack: true })); // read await queue.add(() => this.setState('energy.phase2.power_coefficient', { val: parseInt(o.nrg[13], 10), ack: true })); // read await queue.add(() => this.setState('energy.phase3.power_coefficient', { val: parseInt(o.nrg[14], 10), ack: true })); // read await queue.add(() => this.setState('energy.neutral.power_coefficient', { val: parseInt(o.nrg[15], 10), ack: true })); // read break; case 'cbl': await queue.add(() => this.setState('cable_ampere_code', { val: parseInt(o.cbl), ack: true })); // read break; case 'amt': await queue.add(() => this.setState('avail_ampere', { val: parseInt(o.amt, 10), ack: true })); break; case 'eto': await queue.add(() => this.setState('energy.total', { val: (o.eto / 10), ack: true })); // read break; case 'wst': await queue.add(() => this.setState('wifi.state', { val: parseInt(o.wst, 10), ack: true })); // read break; case 'txi': await queue.add(() => this.setState('transmit_interface', { val: o.txi, ack: true })); break; case 'wss': await queue.add(() => this.setState('wifi.ssid', { val: o.wss, ack: true })); // write break; case 'wke': await queue.add(() => this.setState('wifi.key', { val: o.wke, ack: true })); // write break; case 'wen': await queue.add(() => this.setState('wifi.enabled', { val: parseInt(o.wen, 10), ack: true })); // write break; case 'cdi': await queue.add(() => this.setState('cloud_disabled', { val: parseInt(o.cdi, 10), ack: true })); break; case 'wak': await queue.add(() => this.setState('wifi.hotspot_key', { val: o.wak, ack: true })); // write break; case 'r1x': await queue.add(() => this.setState('http_flags', { val: parseInt(o.r1x, 10), ack: true })); // write break; case 'dws': await queue.add(() => this.setState('loaded_energy', { val: parseInt(o.dws, 10), ack: true })); // read if(/^050/.test(o.fwv)) { await queue.add(() => this.setState('loaded_energy_kwh', { val: o.dws / 100, ack: true})); } else { await queue.add(() => this.setState('loaded_energy_kwh', { val: o.dws * 10 / 60 / 60 / 1000, ack: true})); } break; case 'dwo': await queue.add(() => this.setState('max_load', { val: (o.dwo / 10), ack: true })); // write break; case 'aho': await queue.add(() => this.setState('electricity_exchange.min_hours', { val: parseInt(o.aho, 10), ack: true })); // write break; case 'afi': await queue.add(() => this.setState('electricity_exchange.finish_hour', { val: parseInt(o.afi, 10), ack: true })); // write break; case 'azo': await queue.add(() => this.setState('electricity_exchange.price_zone', { val: parseInt(o.azo, 10), ack: true })); break; case 'ama': await queue.add(() => this.setState('max_ampere', { val: parseInt(o.ama, 10), ack: true })); break; case 'fwv': await queue.add(() => this.setState('firmware_version', { val: o.fwv, ack: true })); // read break; case 'sse': await queue.add(() => this.setState('serial_number', { val: o.sse, ack: true })); // read break; case 'lbr': await queue.add(() => this.setState('settings.color.led_brightness', { val: parseInt(o.lbr, 10), ack: true })); // write break; case 'al1': await queue.add(() => this.setState('settings.ampere_level1', { val: parseInt(o.al1, 10), ack: true })); // write break; case 'al2': await queue.add(() => this.setState('settings.ampere_level2', { val: parseInt(o.al2, 10), ack: true })); // write break; case 'al3': await queue.add(() => this.setState('settings.ampere_level3', { val: parseInt(o.al3, 10), ack: true })); // write break; case 'al4': await queue.add(() => this.setState('settings.ampere_level4', { val: parseInt(o.al4, 10), ack: true })); // write break; case 'al5': await queue.add(() => this.setState('settings.ampere_level5', { val: parseInt(o.al5, 10), ack: true })); // write break; case 'cid': await queue.add(() => this.setState('settings.color.idle', { val: '#' + ('000000' + parseInt(o.cid, 10).toString(16)).slice(6), ack: true })); // write break; case 'cch': await queue.add(() => this.setState('settings.color.charging', { val: '#' + ('000000' + parseInt(o.cch, 10).toString(16)).slice(6), ack: true })); // write break; case 'cfi': await queue.add(() => this.setState('settings.color.finish', { val: '#' + ('000000' + parseInt(o.cfi, 10).toString(16)).slice(6), ack: true })); // write break; case 'tof': await queue.add(() => this.setState('time_offset', { val: parseInt(o.tof, 10), ack: true})); // write break; case 'tds': await queue.add(() => this.setState('time_daylight_saving', { val: parseInt(o.tds, 10), ack: true })); // write break; case 'eca': // RFID Badges await queue.add(() => this.setState('rfid.badges.1.consumption', { val: (o.eca / 10), ack: true })); // read break; case 'ecr': await queue.add(() => this.setState('rfid.badges.2.consumption', { val: (o.ecr / 10), ack: true })); // read break; case 'ecd': await queue.add(() => this.setState('rfid.badges.3.consumption', { val: (o.ecd / 10), ack: true })); // read break; case 'ec4': await queue.add(() => this.setState('rfid.badges.4.consumption', { val: (o.ec4 / 10), ack: true })); // read break; case 'ec5': await queue.add(() => this.setState('rfid.badges.5.consumption', { val: (o.ec5 / 10), ack: true })); // read break; case 'ec6': await queue.add(() => this.setState('rfid.badges.6.consumption', { val: (o.ec6 / 10), ack: true })); // read break; case 'ec7': await queue.add(() => this.setState('rfid.badges.7.consumption', { val: (o.ec7 / 10), ack: true })); // read break; case 'ec8': await queue.add(() => this.setState('rfid.badges.8.consumption', { val: (o.ec8 / 10), ack: true })); // read break; case 'ec9': await queue.add(() => this.setState('rfid.badges.9.consumption', { val: (o.ec9 / 10), ack: true })); // read break; case 'ec1': await queue.add(() => this.setState('rfid.badges.10.consumption', { val: (o.ec1 / 10), ack: true })); // read break; case 'rca': await queue.add(() => this.setState('rfid.badges.1.id', { val: o.rca, ack: true })); // read break; case 'rcr': await queue.add(() => this.setState('rfid.badges.2.id', { val: o.rcr, ack: true })); // read break; case 'rcd': await queue.add(() => this.setState('rfid.badges.3.id', { val: o.rcd, ack: true })); // read break; case 'rc4': await queue.add(() => this.setState('rfid.badges.4.id', { val: o.rc4, ack: true })); // read break; case 'rc5': await queue.add(() => this.setState('rfid.badges.5.id', { val: o.rc5, ack: true })); // read break; case 'rc6': await queue.add(() => this.setState('rfid.badges.6.id', { val: o.rc6, ack: true })); // read break; case 'rc7': await queue.add(() => this.setState('rfid.badges.7.id', { val: o.rc7, ack: true })); // read break; case 'rc8': await queue.add(() => this.setState('rfid.badges.8.id', { val: o.rc8, ack: true })); // read break; case 'rc9': await queue.add(() => this.setState('rfid.badges.9.id', { val: o.rc9, ack: true })); // read break; case 'rc1': await queue.add(() => this.setState('rfid.badges.10.id', { val: o.rc1, ack: true })); // read break; case 'rna': // RFID Name await queue.add(() => this.setState('rfid.badges.1.name', { val: o.rna, ack: true })); // write break; case 'rnm': await queue.add(() => this.setState('rfid.badges.2.name', { val: o.rnm, ack: true })); // write break; case 'rne': await queue.add(() => this.setState('rfid.badges.3.name', { val: o.rne, ack: true })); // write break; case 'rn4': await queue.add(() => this.setState('rfid.badges.4.name', { val: o.rn4, ack: true })); // write break; case 'rn5': await queue.add(() => this.setState('rfid.badges.5.name', { val: o.rn5, ack: true })); // write break; case 'rn6': await queue.add(() => this.setState('rfid.badges.6.name', { val: o.rn6, ack: true })); // write break; case 'rn7': await queue.add(() => this.setState('rfid.badges.7.name', { val: o.rn7, ack: true })); // write break; case 'rn8': await queue.add(() => this.setState('rfid.badges.8.name', { val: o.rn8, ack: true })); // write break; case 'rn9': await queue.add(() => this.setState('rfid.badges.9.name', { val: o.rn9, ack: true })); // write break; case 'rn1': await queue.add(() => this.setState('rfid.badges.10.name', { val: o.rn1, ack: true })); // write break; case 'mce': await queue.add(() => this.setState('mqtt.enabled', { val: parseInt(o.mce, 10), ack: true })); break; case 'mcs': await queue.add(() => this.setState('mqtt.server', { val: o.mcs, ack: true })); break; case 'mcp': await queue.add(() => this.setState('mqtt.port', { val: o.mcp, ack: true })); break; case 'mcu': await queue.add(() => this.setState('mqtt.user', { val: o.mcu, ack: true })); break; case 'mck': await queue.add(() => this.setState('mqtt.key', { val: o.mck, ack: true })); break; case 'mcc': await queue.add(() => this.setState('mqtt.connection', { val: o.mcc, ack: true })); break; case 'tmp': await queue.add(() => this.setState('temperatures.maintemperature', { val: parseInt(o.tmp, 10), ack: true })); // read break; case 'tma': try { let tempArr = o.tma.toString().split(','); for(let i = 0; i<tempArr.length; i++) { const tmpObj = await this.getObjectAsync('temperatures.temperature' + (i+1)); this.log.silly('temperatures.temperature' + (i+1) + ': ' + JSON.stringify(tmpObj)); if ( tmpObj == null) { const obj = { name: 'temperatures.temperature' + (i+1), type: 'number', read: true, write: false, role: 'value.temperature', desc: 'Temperature Sensor' };