homebridge-jablotron-mqtt
Version:
Plugin for Jablotron JA-6X system communicating via mqtt and py-jablotron6x
241 lines • 11.2 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JbMqttAccPlg = void 0;
const mqtt = __importStar(require("mqtt"));
const const_1 = require("./const");
const settings_1 = require("./settings");
var JbMqttCustomConfigKeys;
(function (JbMqttCustomConfigKeys) {
JbMqttCustomConfigKeys["SECURITY_CODE"] = "securityCode";
JbMqttCustomConfigKeys["MQTT_USERNAME"] = "username";
JbMqttCustomConfigKeys["MQTT_PASSWORD"] = "password";
JbMqttCustomConfigKeys["MQTT_URL"] = "mqttUrl";
JbMqttCustomConfigKeys["MQTT_TOPIC_PREFIX"] = "mqttTopicPrefix";
JbMqttCustomConfigKeys["MQTT_START_CMD"] = "startCmd";
JbMqttCustomConfigKeys["MQTT_START_PARAM"] = "startParameter";
JbMqttCustomConfigKeys["MODEL"] = "MODEL";
JbMqttCustomConfigKeys["ALLOW_COMMUNICATION"] = "allowCommunication";
})(JbMqttCustomConfigKeys || (JbMqttCustomConfigKeys = {}));
class JbMqttAccPlg {
constructor(logger, config, api) {
this.currentState = 3; //Characteristic.SecuritySystemCurrentState.DISARMED;
this.client_Id = 'mqttjs_' + Math.random().toString(16).substr(2, 8);
this.mqttOptions = {};
this.allowCommunication = false;
this.runningChangeCallback = undefined;
this.runningChangeTarget = undefined;
this.changeState = async (target) => {
await this.asyncPublish(const_1.AlarmTopic.KEY_PRESS, const_1.Command.CLEAR);
if (target === const_1.JblMode.ARMED) {
await this.asyncPublish(const_1.AlarmTopic.KEY_PRESS, const_1.Command.ARM);
}
else if (target === const_1.JblMode.DISARMED) {
await this.asyncPublish(const_1.AlarmTopic.KEY_PRESS, this.securityCode);
}
};
this.log = logger;
this.Service = api.hap.Service;
this.Characteristic = api.hap.Characteristic;
this.name = config.name;
this.model = config[JbMqttCustomConfigKeys.MODEL];
this.securityCode = config[JbMqttCustomConfigKeys.SECURITY_CODE];
this.mqttOptions = {
keepalive: 10,
clientId: this.client_Id,
protocolId: 'MQTT',
protocolVersion: 4,
clean: true,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
will: {
topic: 'WillMsg',
payload: 'Connection Closed abnormally..!',
qos: 0,
retain: false,
},
username: config[JbMqttCustomConfigKeys.MQTT_USERNAME],
password: config[JbMqttCustomConfigKeys.MQTT_PASSWORD],
rejectUnauthorized: false,
};
this.mqttUrl = config[JbMqttCustomConfigKeys.MQTT_URL];
this.mqttTopicPrefix = config[JbMqttCustomConfigKeys.MQTT_TOPIC_PREFIX] || '';
this.mqttTopics = [this.getTopic(const_1.AlarmTopic.RAW), this.getTopic(const_1.AlarmTopic.MODE)];
this.client = mqtt.connect(this.mqttUrl, this.mqttOptions);
this.allowCommunication = config[JbMqttCustomConfigKeys.ALLOW_COMMUNICATION];
this.log('Subsribing to', this.mqttTopics);
this.client.subscribe(this.mqttTopics);
const securityStateService = new api.hap.Service.SecuritySystem(settings_1.ACCESSORY_NAME, 'MODEL TODO');
securityStateService
.getCharacteristic(api.hap.Characteristic.SecuritySystemCurrentState)
.on("get" /* GET */, this.getCurrentState.bind(this));
securityStateService
.getCharacteristic(api.hap.Characteristic.SecuritySystemTargetState)
.on("get" /* GET */, this.getTargetState.bind(this))
.on("set" /* SET */, this.setTargetState.bind(this));
this.securityStateService = securityStateService;
const informationService = new api.hap.Service.AccessoryInformation();
informationService
.setCharacteristic(api.hap.Characteristic.Name, this.name)
.setCharacteristic(api.hap.Characteristic.Manufacturer, const_1.MANUFACTURER)
.setCharacteristic(api.hap.Characteristic.Model, this.model)
.setCharacteristic(api.hap.Characteristic.SerialNumber, '-');
this.informationService = informationService;
this.client.on('error', () => {
this.log('Error event on MQTT');
});
this.client.on('connect', () => {
if (config['startCmd'] !== undefined && config['startParameter'] !== undefined) {
this.client.publish(config[JbMqttCustomConfigKeys.MQTT_START_CMD], config[JbMqttCustomConfigKeys.MQTT_START_PARAM]);
}
});
this.client.on('message', (topic, message) => {
const text = message.toString();
if (topic === this.getTopic(const_1.AlarmTopic.RAW)) {
//Raw
/// e0 41 11 59 29 03 3d ff
/*
00 1 byte e0/e1/e2 - general status
01 1 byte mode
02 1 byte binary status of leds ???
03 1 byte content of display ???
04 1 byte strength of GSM signal/battery??
05 1 byte zero one or two
06 1 byte checksum
07 1 byte 0xFF - indicates end of message
*/
const arrE0 = text.split(' ');
if (arrE0.length === 8) {
if (arrE0[0] === const_1.JablotronRecordType.STATUS) {
let newState = undefined;
let stateName;
const jblMode = arrE0[1];
switch (jblMode) {
case const_1.JblMode.ARMED:
newState = this.Characteristic.SecuritySystemCurrentState.AWAY_ARM;
stateName = 'AWAY_ARM';
break;
case const_1.JblMode.DISARMED:
newState = this.Characteristic.SecuritySystemCurrentState.DISARMED;
stateName = 'DISARMED';
break;
case const_1.JblMode.TAMPERED:
case const_1.JblMode.TRIGGERED:
newState = this.Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED;
stateName = 'ALARM_TRIGGERED';
break;
default:
stateName = 'UNKNOWN';
//change = false;
}
if (newState !== undefined) {
if (this.runningChangeCallback !== undefined && jblMode === this.runningChangeTarget) {
try {
this.runningChangeCallback(null, newState);
}
catch (e) {
this.log('Error sending event back to callback from raw', e);
this.runningChangeCallback = undefined;
}
}
if (newState !== this.currentState) {
this.log('setting new state', stateName);
this.currentState = newState;
this.securityStateService
.getCharacteristic(api.hap.Characteristic.SecuritySystemCurrentState)
.setValue(this.currentState, 'fromSetValue');
}
}
}
}
}
});
}
async asyncPublish(topic, message, opts = {}) {
return new Promise((resolve, reject) => {
this.client.publish(this.getTopic(topic), message, opts, (error, packet) => {
if (error) {
reject(error);
}
else {
resolve(packet);
}
});
});
}
getTopic(name) {
return this.mqttTopicPrefix + '/' + name;
}
getServices() {
return [this.securityStateService, this.informationService];
}
getCurrentState(callback) {
callback(null, this.currentState);
}
getTargetState(callback) {
callback(null, this.currentState);
}
setTargetState(state, callback) {
this.log('Getting current state');
if (this.runningChangeCallback !== undefined) {
this.runningChangeTarget = undefined;
this.runningChangeCallback(new Error('Cancelled'));
this.runningChangeCallback = undefined;
}
if (this.currentState === state) {
callback(null, state);
return;
}
let targetState = undefined;
switch (state) {
case this.Characteristic.SecuritySystemTargetState.STAY_ARM:
case this.Characteristic.SecuritySystemTargetState.AWAY_ARM:
case this.Characteristic.SecuritySystemTargetState.NIGHT_ARM:
targetState = const_1.JblMode.ARMED;
break;
case this.Characteristic.SecuritySystemTargetState.DISARM:
targetState = const_1.JblMode.DISARMED;
break;
}
if (!this.allowCommunication) {
this.log('Communication is forbiden', 'current state:', this.currentState, 'new state:', targetState);
callback(new Error('Communication is forbiden'));
return;
}
if (!this.client.connected) {
this.log('MQTT is not connected');
callback(new Error('MQTT is not connected'));
return;
}
if (targetState !== undefined) {
this.runningChangeTarget = targetState;
this.runningChangeCallback = callback;
this.changeState(targetState).catch(e => {
this.runningChangeTarget = undefined;
this.runningChangeCallback = undefined;
callback(e, null);
this.log('Error in invoke', e);
});
}
}
}
exports.JbMqttAccPlg = JbMqttAccPlg;
//# sourceMappingURL=accessory.js.map