diff --git a/src/devices/sonoff.ts b/src/devices/sonoff.ts index bce3fd8fe22b9..f6b5b94f06746 100644 --- a/src/devices/sonoff.ts +++ b/src/devices/sonoff.ts @@ -4,11 +4,12 @@ import fz from '../converters/fromZigbee'; import tz from '../converters/toZigbee'; import * as constants from '../lib/constants'; import * as reporting from '../lib/reporting'; -import {binary, enumLookup, forcePowerSource, numeric, onOff, customTimeResponse, battery} from '../lib/modernExtend'; +import {binary, enumLookup, forcePowerSource, numeric, onOff, customTimeResponse, battery, ota} from '../lib/modernExtend'; import {Definition, Fz, KeyValue, KeyValueAny, ModernExtend, Tz} from '../lib/types'; -import * as ota from '../lib/ota'; import * as utils from '../lib/utils'; import {logger} from '../lib/logger'; +import {modernExtend as ewelinkModernExtend} from '../lib/ewelink'; +const {ewelinkAction} = ewelinkModernExtend; const NS = 'zhc:sonoff'; const e = exposes.presets; @@ -405,8 +406,10 @@ const definitions: Definition[] = [ model: 'ZBMINI-L', vendor: 'SONOFF', description: 'Zigbee smart switch (no neutral)', - ota: ota.zigbeeOTA, - extend: [onOff()], + extend: [ + onOff(), + ota(), + ], configure: async (device, coordinatorEndpoint) => { // Unbind genPollCtrl to prevent device from sending checkin message. // Zigbee-herdsmans responds to the checkin message which causes the device @@ -422,8 +425,10 @@ const definitions: Definition[] = [ model: 'ZBMINIL2', vendor: 'SONOFF', description: 'Zigbee smart switch (no neutral)', - ota: ota.zigbeeOTA, - extend: [onOff()], + extend: [ + onOff(), + ota(), + ], configure: async (device, coordinatorEndpoint) => { // Unbind genPollCtrl to prevent device from sending checkin message. // Zigbee-herdsmans responds to the checkin message which causes the device @@ -600,7 +605,10 @@ const definitions: Definition[] = [ model: 'S40ZBTPB', vendor: 'SONOFF', description: '15A Zigbee smart plug', - extend: [onOff({powerOnBehavior: false, skipDuplicateTransaction: true, ota: ota.zigbeeOTA})], + extend: [ + onOff({powerOnBehavior: false, skipDuplicateTransaction: true}), + ota(), + ], }, { zigbeeModel: ['DONGLE-E_R'], @@ -637,16 +645,17 @@ const definitions: Definition[] = [ model: 'SNZB-01P', vendor: 'SONOFF', description: 'Wireless button', - exposes: [e.battery(), e.action(['single', 'double', 'long']), e.battery_low(), e.battery_voltage()], - fromZigbee: [fz.ewelink_action, fz.battery], - toZigbee: [], - ota: ota.zigbeeOTA, - configure: async (device, coordinatorEndpoint) => { - const endpoint = device.getEndpoint(1); - await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genPowerCfg']); - await reporting.batteryVoltage(endpoint, {min: 3600, max: 7200}); - await reporting.batteryPercentageRemaining(endpoint, {min: 3600, max: 7200}); - }, + extend: [ + forcePowerSource({powerSource: 'Battery'}), + ewelinkAction(), + battery({ + percentageReportingConfig: {min: 3600, max: 7200, change: 0}, + voltage: true, + voltageReporting: true, + voltageReportingConfig: {min: 3600, max: 7200, change: 0}, + }), + ota(), + ], }, { zigbeeModel: ['SNZB-02P'], @@ -655,8 +664,6 @@ const definitions: Definition[] = [ description: 'Temperature and humidity sensor', exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_low(), e.battery_voltage()], fromZigbee: [fz.temperature, fz.humidity, fz.battery], - toZigbee: [], - ota: ota.zigbeeOTA, configure: async (device, coordinatorEndpoint) => { try { const endpoint = device.getEndpoint(1); @@ -669,6 +676,9 @@ const definitions: Definition[] = [ logger.error(`Configure failed: ${e}`, NS); } }, + extend: [ + ota(), + ], }, { zigbeeModel: ['SNZB-04P'], @@ -677,8 +687,6 @@ const definitions: Definition[] = [ description: 'Contact sensor', exposes: [e.contact(), e.battery_low(), e.battery(), e.battery_voltage()], fromZigbee: [fz.ias_contact_alarm_1, fz.battery], - toZigbee: [], - ota: ota.zigbeeOTA, extend: [ binary({ name: 'tamper', @@ -690,6 +698,7 @@ const definitions: Definition[] = [ zigbeeCommandOptions: {manufacturerCode: Zcl.ManufacturerCode.SHENZHEN_COOLKIT_TECHNOLOGY_CO_LTD}, access: 'STATE_GET', }), + ota(), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); @@ -704,8 +713,6 @@ const definitions: Definition[] = [ vendor: 'SONOFF', description: 'Zigbee PIR sensor', fromZigbee: [fz.occupancy, fz.battery], - toZigbee: [], - ota: ota.zigbeeOTA, exposes: [e.occupancy(), e.battery_low(), e.battery()], extend: [ numeric({ @@ -725,6 +732,7 @@ const definitions: Definition[] = [ description: 'Only updated when occupancy is detected', access: 'STATE', }), + ota(), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); @@ -739,8 +747,6 @@ const definitions: Definition[] = [ vendor: 'SONOFF', description: 'Zigbee occupancy sensor', fromZigbee: [fz.occupancy], - toZigbee: [], - ota: ota.zigbeeOTA, exposes: [e.occupancy()], extend: [ numeric({ @@ -767,6 +773,7 @@ const definitions: Definition[] = [ zigbeeCommandOptions: {manufacturerCode: Zcl.ManufacturerCode.SHENZHEN_COOLKIT_TECHNOLOGY_CO_LTD}, access: 'STATE', }), + ota(), ], }, { @@ -795,7 +802,6 @@ const definitions: Definition[] = [ tz.thermostat_system_mode, tz.thermostat_running_state, ], - ota: ota.zigbeeOTA, extend: [ binary({ name: 'child_lock', @@ -865,6 +871,7 @@ const definitions: Definition[] = [ }), sonoffExtend.weeklySchedule(), customTimeResponse('1970_UTC'), + ota(), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); @@ -898,8 +905,6 @@ const definitions: Definition[] = [ fromZigbee: [ fz.flow, ], - toZigbee: [], - ota: ota.zigbeeOTA, exposes: [ e.numeric('flow', ea.STATE).withDescription('Current water flow').withUnit('m³/h'), ], @@ -920,6 +925,7 @@ const definitions: Definition[] = [ }), sonoffExtend.cyclicTimedIrrigation(), sonoffExtend.cyclicQuantitativeIrrigation(), + ota(), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); @@ -933,7 +939,6 @@ const definitions: Definition[] = [ model: 'ZBMicro', vendor: 'SONOFF', description: 'Zigbee USB repeater plug', - ota: ota.zigbeeOTA, extend: [ onOff(), binary({ @@ -946,6 +951,7 @@ const definitions: Definition[] = [ valueOn: [true, 0x14], }), sonoffExtend.inchingControlSet(), + ota(), ], }, ]; diff --git a/src/lib/ewelink.ts b/src/lib/ewelink.ts new file mode 100644 index 0000000000000..698be5c0785a1 --- /dev/null +++ b/src/lib/ewelink.ts @@ -0,0 +1,26 @@ +import {Expose, Fz, ModernExtend, KeyValueAny, Configure} from './types'; +import {presets} from './exposes'; +import {setupConfigureForBinding} from './modernExtend'; + +export const ewelinkModernExtend = { + ewelinkAction: (): ModernExtend => { + const exposes: Expose[] = [presets.action(['single', 'double', 'long'])]; + + const fromZigbee: Fz.Converter[] = [ + { + cluster: 'genOnOff', + type: ['commandOn', 'commandOff', 'commandToggle'], + convert: (model, msg, publish, options, meta) => { + const lookup: KeyValueAny = {'commandToggle': 'single', 'commandOn': 'double', 'commandOff': 'long'}; + return {action: lookup[msg.type]}; + }, + }, + ]; + + const configure: Configure = setupConfigureForBinding('genOnOff', 'output'); + + return {exposes, fromZigbee, configure, isModernExtend: true}; + }, +}; + +export {ewelinkModernExtend as modernExtend};