homebridge-tasmota
Version:
Homebridge plugin for Tasmota devices leveraging home assistant auto discovery.
188 lines (187 loc) • 10.4 kB
JavaScript
import createDebug from 'debug';
import { TasmotaService } from './TasmotaService.js';
const debug = createDebug('Tasmota:garage');
/**
* Platform Accessory
* An instance of this class is created for each accessory your platform registers
* Each accessory may expose multiple services of different service types.
*/
export class tasmotaGarageService extends TasmotaService {
platform;
accessory;
uniq_id;
doorStatusTopic;
doorSensorTopic;
constructor(platform, accessory, uniq_id) {
super(platform, accessory, uniq_id);
this.platform = platform;
this.accessory = accessory;
this.uniq_id = uniq_id;
this.service = this.accessory.getService(this.uuid) || this.accessory.addService(this.platform.Service.GarageDoorOpener, accessory.context.device[this.uniq_id].name, this.uuid);
this.service?.setCharacteristic(this.platform.Characteristic.ConfiguredName, accessory.context.device[this.uniq_id].name);
// set the service name, this is what is displayed as the default name on the Home app
// in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
if (!this.service?.displayName) {
this.service?.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device[this.uniq_id].name);
}
// each service must implement at-minimum the "required characteristics" for the given service type
// see https://developers.homebridge.io/#/service/Lightbulb
this.characteristic = this.service?.getCharacteristic(this.platform.Characteristic.CurrentDoorState);
this.enableFakegato();
// register handlers for the On/Off Characteristic
if (this.service?.getCharacteristic(this.platform.Characteristic.TargetDoorState).listenerCount('set') < 1) {
this.service?.getCharacteristic(this.platform.Characteristic.TargetDoorState)
.on('set', this.setDoorState.bind(this)); // SET - bind to the `setOn` method below
// .on('get', this.getOn.bind(this)); // GET - bind to the `getOn` method below
}
this.enableStatus();
this.doorStatusTopic = this.accessory.context.device[this.uniq_id].stat_t.replace('STATE', 'DOOR');
this.platform.mqttHost.on(this.doorStatusTopic, this.statusUpdate.bind(this));
this.platform.mqttHost.statusSubscribe(this.doorStatusTopic);
this.doorSensorTopic = this.accessory.context.device[this.uniq_id].stat_t.replace('STATE', 'SENSOR');
this.platform.mqttHost.on(this.doorSensorTopic, this.statusUpdate.bind(this));
this.platform.mqttHost.statusSubscribe(this.doorSensorTopic);
}
/**
enableStatus() {
this.refresh();
if (this.characteristic) {
if (this.accessory.context.device[this.uniq_id].stat_t) {
this.platform.log.debug('Creating statusUpdate listener for %s %s', this.accessory.context.device[this.uniq_id].stat_t,
this.accessory.context.device[this.uniq_id].name);
this.statusSubscribe = { event: this.accessory.context.device[this.uniq_id].stat_t, callback: this.statusUpdate.bind(this) };
this.platform.mqttHost.on(this.accessory.context.device[this.uniq_id].stat_t, this.statusUpdate.bind(this));
this.platform.mqttHost.statusSubscribe(this.accessory.context.device[this.uniq_id].stat_t);
}
if (this.accessory.context.device[this.uniq_id].avty_t) {
this.availabilitySubscribe = { event: this.accessory.context.device[this.uniq_id].avty_t,
callback: this.availabilityUpdate.bind(this) };
this.platform.mqttHost.on(this.accessory.context.device[this.uniq_id].avty_t, this.availabilityUpdate.bind(this));
this.availabilitySubscribe =
this.platform.mqttHost.availabilitySubscribe(this.accessory.context.device[this.uniq_id].avty_t);
} else {
this.platform.log.warn('Warning: Availability not supported for: %s', this.accessory.context.device[this.uniq_id].name);
}
}
}
*/
/**
* Handle "STATE" messages from Tasmotastat_t:
* These are sent when the device's state is changed, either via HomeKit, Local Control or Other control methods.
*/
statusUpdate(topic, message) {
debug('MQTT', topic, message.toString());
try {
this.accessory.context.timeout = this.platform.autoCleanup(this.accessory);
let value = message.toString();
switch (topic) {
case this.doorStatusTopic:
debug('doorStatusTopic \'%s:%s\'', this.service?.displayName, this.characteristic?.displayName);
switch (value) {
case 'CLOSED':
value = this.platform.Characteristic.CurrentDoorState.CLOSED;
break;
case 'OPEN':
value = this.platform.Characteristic.CurrentDoorState.OPEN;
break;
case 'CLOSING':
value = this.platform.Characteristic.CurrentDoorState.CLOSING;
break;
case 'OPENING':
value = this.platform.Characteristic.CurrentDoorState.OPENING;
break;
default:
this.platform.log.error('Unhandled Garage Door Status', value);
}
if (this.characteristic?.value !== value) {
this.platform.log.info('Updating \'%s:%s\' to %s', this.service?.displayName, this.characteristic?.displayName, value);
}
else {
this.platform.log.debug('Updating \'%s\' to %s', this.service?.displayName, value);
}
this.characteristic?.updateValue(value);
if (topic === this.doorStatusTopic || topic === this.doorSensorTopic) {
this.service?.getCharacteristic(this.platform.Characteristic.TargetDoorState).updateValue(Number(value) % 2);
}
break;
case this.doorSensorTopic:
{
debug('doorSensorTopic \'%s:%s\'', this.service?.displayName, this.characteristic?.displayName);
const parsedValue = JSON.parse(value);
debug('doorSensorTopic %s', value);
if (parsedValue.Switch2 === 'OFF') {
value = this.platform.Characteristic.CurrentDoorState.OPEN;
if (this.characteristic?.value !== value) {
this.platform.log.info('Updating \'%s:%s\' to %s', this.service?.displayName, this.characteristic?.displayName, value);
}
else {
this.platform.log.debug('Updating \'%s\' to %s', this.service?.displayName, value);
}
this.characteristic?.updateValue(value);
if (topic === this.doorStatusTopic || topic === this.doorSensorTopic) {
this.service?.getCharacteristic(this.platform.Characteristic.TargetDoorState).updateValue(value % 2);
}
}
else if (parsedValue.Switch3 === 'OFF') {
value = this.platform.Characteristic.CurrentDoorState.CLOSED;
if (this.characteristic?.value !== value) {
this.platform.log.info('Updating \'%s:%s\' to %s', this.service?.displayName, this.characteristic?.displayName, value);
}
else {
this.platform.log.debug('Updating \'%s\' to %s', this.service?.displayName, value);
}
this.characteristic?.updateValue(value);
if (topic === this.doorStatusTopic || topic === this.doorSensorTopic) {
this.service?.getCharacteristic(this.platform.Characteristic.TargetDoorState).updateValue(value % 2);
}
}
else {
this.platform.log.info('Not open or closed \'%s:%s\'', this.service?.displayName, this.characteristic?.displayName);
}
break;
}
default:
}
}
catch (err) {
this.platform.log.error('ERROR: message parsing error', this.service?.displayName, topic, message.toString());
}
}
/**
* Handle "SET" requests from HomeKit
* These are sent when the user changes the state of an accessory, for example, turning on a Light bulb.
*/
setDoorState(value, callback) {
try {
if (this.service?.getCharacteristic(this.platform.Characteristic.TargetDoorState).value !== value) {
this.platform.log.info('%s Pushing Garage Door Button ->', this.service?.displayName, value);
this.platform.mqttHost.sendMessage(this.accessory.context.device[this.uniq_id].cmd_t, this.accessory.context.device[this.uniq_id].pl_on);
}
else {
this.platform.log.error('%s Not Pushing Garage Door Button ->', this.service?.displayName, value);
}
}
catch (err) {
this.platform.log.debug(String((err && err.message ? err.message : err)));
}
// you must call the callback function
callback(null);
}
}
/*
Tasmota:platform Discovered -> homeassistant/switch/FB6A07_RL_1/config Garage Door {
name: 'Garage Door',
stat_t: 'tele/tasmota_FB6A07/STATE',
avty_t: 'tele/tasmota_FB6A07/LWT',
pl_avail: 'Online',
pl_not_avail: 'Offline',
cmd_t: 'cmnd/tasmota_FB6A07/POWER',
val_tpl: '{{value_json.POWER}}',
pl_off: 'OFF',
pl_on: 'ON',
uniq_id: 'FB6A07_RL_1',
dev: { ids: [ 'FB6A07' ] },
tasmotaType: 'garageDoor'
}
*/
//# sourceMappingURL=tasmotaGarageService.js.map