Skip to content

Commit

Permalink
Merge branch 'master' into bac-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
a2nt authored Dec 6, 2023
2 parents 38f71e2 + ddf7dcf commit 4f8df9d
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 66 deletions.
23 changes: 19 additions & 4 deletions src/converters/fromZigbee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4860,7 +4860,12 @@ const converters1 = {
DJT11LM_vibration: {
cluster: 'closuresDoorLock',
type: ['attributeReport', 'readResponse'],
options: [exposes.options.vibration_timeout()],
options: [
exposes.options.vibration_timeout(),
exposes.options.calibration('x'),
exposes.options.calibration('y'),
exposes.options.calibration('z'),
],
convert: (model, msg, publish, options, meta) => {
const result: KeyValueAny = {};

Expand Down Expand Up @@ -4911,10 +4916,20 @@ const converters1 = {
// data[1][bit16..bit31]: y
// data[0][bit0..bit15] : z
// left shift first to preserve sign extension for 'x'
const x = ((data['1'] << 16) >> 16);
const y = (data['1'] >> 16);
let x = ((data['1'] << 16) >> 16);
let y = (data['1'] >> 16);
// left shift first to preserve sign extension for 'z'
const z = ((data['0'] << 16) >> 16);
let z = ((data['0'] << 16) >> 16);

// simple offset calibration
x=calibrateAndPrecisionRoundOptions(x, options, 'x');
y=calibrateAndPrecisionRoundOptions(y, options, 'y');
z=calibrateAndPrecisionRoundOptions(z, options, 'z');

// calibrated accelerometer values
result.x_axis=x;
result.y_axis=y;
result.z_axis=z;

// calculate angle
result.angle_x = Math.round(Math.atan(x/Math.sqrt(y*y+z*z)) * 180 / Math.PI);
Expand Down
8 changes: 3 additions & 5 deletions src/converters/toZigbee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2236,7 +2236,7 @@ const converters2 = {
'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG19LM', 'QBKG18LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM', 'QBKG28LM', 'QBKG29LM',
'QBKG30LM', 'QBKG31LM', 'QBKG32LM', 'QBKG34LM', 'QBKG38LM', 'QBKG39LM', 'QBKG40LM', 'QBKG41LM', 'ZNDDMK11LM', 'ZNLDP13LM',
'ZNQBKG31LM', 'WS-USC02', 'WS-USC03', 'WS-USC04', 'ZNQBKG24LM', 'ZNQBKG25LM', 'JWDL001A', 'SSWQD02LM', 'SSWQD03LM',
'XDD11LM', 'XDD12LM', 'XDD13LM', 'ZNLDP12LM', 'ZNLDP13LM', 'ZNXDD01LM',
'XDD11LM', 'XDD12LM', 'XDD13LM', 'ZNLDP12LM', 'ZNLDP13LM', 'ZNXDD01LM', 'WS-USC01',
].includes(meta.mapped.model)) {
await entity.write('aqaraOpple', {0x0201: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
} else if (['ZNCZ02LM', 'QBCZ11LM', 'LLKZMK11LM'].includes(meta.mapped.model)) {
Expand All @@ -2263,7 +2263,7 @@ const converters2 = {
'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG19LM', 'QBKG18LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM', 'QBKG28LM', 'QBKG29LM',
'QBKG30LM', 'QBKG31LM', 'QBKG32LM', 'QBKG34LM', 'QBKG38LM', 'QBKG39LM', 'QBKG40LM', 'QBKG41LM', 'ZNDDMK11LM', 'ZNLDP13LM',
'ZNQBKG31LM', 'WS-USC02', 'WS-USC03', 'WS-USC04', 'ZNQBKG24LM', 'ZNQBKG25LM', 'JWDL001A', 'SSWQD02LM', 'SSWQD03LM',
'XDD11LM', 'XDD12LM', 'XDD13LM', 'ZNLDP12LM', 'ZNLDP13LM', 'ZNXDD01LM',
'XDD11LM', 'XDD12LM', 'XDD13LM', 'ZNLDP12LM', 'ZNLDP13LM', 'ZNXDD01LM', 'WS-USC01',
].includes(meta.mapped.model)) {
await entity.read('aqaraOpple', [0x0201]);
} else if (['ZNCZ02LM', 'QBCZ11LM', 'ZNCZ11LM', 'ZNCZ12LM'].includes(meta.mapped.model)) {
Expand Down Expand Up @@ -2498,9 +2498,8 @@ const converters2 = {
xiaomi_switch_operation_mode_opple: {
key: ['operation_mode'],
convertSet: async (entity, key, value, meta) => {
utils.assertObject(value);
// Support existing syntax of a nested object just for the state field. Though it's quite silly IMO.
const targetValue = value.hasOwnProperty('state') ? value.state : value;
const targetValue = utils.isObject(value) && value.hasOwnProperty('state') ? value.state : value;
// Switches using aqaraOpple 0x0200 on the same endpoints as the onOff clusters.
const lookupState = {control_relay: 0x01, decoupled: 0x00};
await entity.write('aqaraOpple', {0x0200:
Expand Down Expand Up @@ -4105,7 +4104,6 @@ const converters2 = {
scene_store: {
key: ['scene_store'],
convertSet: async (entity, key, value: KeyValueAny, meta) => {
utils.assertGroup(entity);
const isGroup = utils.isGroup(entity);
const groupid = isGroup ? entity.groupID : value.hasOwnProperty('group_id') ? value.group_id : 0;
let sceneid = value;
Expand Down
54 changes: 34 additions & 20 deletions src/devices/ikea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,24 +281,18 @@ const fzLocal = {
} satisfies Fz.Converter,
ikea_dots_click_v2: {
// For remotes with firmware 1.0.32 (20221219)
cluster: 'heimanSpecificScenes',
type: 'raw',
cluster: 'tradfriButton',
type: ['commandAction1', 'commandAction2', 'commandAction3', 'commandAction4', 'commandAction6'],
convert: (model, msg, publish, options, meta) => {
if (!Buffer.isBuffer(msg.data)) return;
let button;
let action;
switch (msg.endpoint.ID) {
case 2: button = '1'; break; // 1 dot
case 3: button = '2'; break; // 2 dot
}
switch (msg.data[4]) {
case 1: action = 'initial_press'; break;
case 2: action = 'long_press'; break;
case 3: action = 'short_release'; break;
case 4: action = 'long_release'; break;
case 6: action = 'double_press'; break;
}

const button = utils.getFromLookup(msg.endpoint.ID, {2: '1', 3: '2'});
const lookup = {
commandAction1: 'initial_press',
commandAction2: 'long_press',
commandAction3: 'short_release',
commandAction4: 'long_release',
commandAction6: 'double_press',
};
const action = utils.getFromLookup(msg.type, lookup);
return {action: `dots_${button}_${action}`};
},
} satisfies Fz.Converter,
Expand Down Expand Up @@ -603,7 +597,10 @@ const definitions: Definition[] = [
model: 'LED1624G9',
vendor: 'IKEA',
description: 'TRADFRI LED bulb E14/E26/E27 600 lumen, dimmable, color, opal white',
extend: tradfriExtend.light_onoff_brightness_colortemp_color(),
extend: tradfriExtend.light_onoff_brightness_colortemp_color({
disableColorTempStartup: true,
colorTempRange: [153, 500], // light is pure RGB (XY), advertise 2000K-6500K
}),
toZigbee: utils.replaceInArray(
tradfriExtend.light_onoff_brightness_colortemp_color().toZigbee,
[tz.light_color_colortemp],
Expand Down Expand Up @@ -1022,7 +1019,15 @@ const definitions: Definition[] = [
model: 'LED1923R5/LED1925G6',
vendor: 'IKEA',
description: 'TRADFRI LED bulb GU10 345 lumen, dimmable, white spectrum, color spectrum',
extend: tradfriExtend.light_onoff_brightness_colortemp_color({colorTempRange: [250, 454]}),
extend: tradfriExtend.light_onoff_brightness_colortemp_color({
disableColorTempStartup: true,
colorTempRange: [153, 500],
}),
toZigbee: utils.replaceInArray(
tradfriExtend.light_onoff_brightness_colortemp_color().toZigbee,
[tz.light_color_colortemp],
[tz.light_color_and_colortemp_via_color],
),
},
{
zigbeeModel: ['TRADFRI bulb E27 WS globe 1055lm'],
Expand Down Expand Up @@ -1061,7 +1066,7 @@ const definitions: Definition[] = [
extend: tradfriExtend.light_onoff_brightness_colortemp(),
},
{
zigbeeModel: ['TRADFRI_bulb_GU10_WS_345lm'],
zigbeeModel: ['TRADFRI_bulb_GU10_WS_345lm', 'TRADFRI bulb GU10 WW 345lm'],
model: 'LED2106R3',
vendor: 'IKEA',
description: 'TRADFRI LED bulb GU10 345 lumen, dimmable, white spectrum',
Expand Down Expand Up @@ -1269,6 +1274,15 @@ const definitions: Definition[] = [
await reporting.illuminance(endpoint3);
},
},
{
zigbeeModel: ['PARASOLL Door/Window Sensor'],
model: 'E2013',
vendor: 'IKEA',
description: 'PARASOLL door/window Sensor',
fromZigbee: [fz.ias_contact_alarm_1],
toZigbee: [],
exposes: [e.battery_low(), e.tamper(), e.contact()],
},
];

export default definitions;
Expand Down
30 changes: 4 additions & 26 deletions src/devices/makegood.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,15 @@
import {Definition, Fz} from '../lib/types';
import * as exposes from '../lib/exposes';
import fz from '../converters/fromZigbee';
import tz from '../converters/toZigbee';
import {Definition} from '../lib/types';
import * as reporting from '../lib/reporting';
import * as tuya from '../lib/tuya';
import * as utils from '../lib/utils';
const e = exposes.presets;

const fzLocal = {
// MG-AUZG01 requires multiEndpoint only for on_off
// https://github.com/Koenkk/zigbee2mqtt/issues/13190
MGAUZG01_on_off: {
cluster: 'genOnOff',
type: ['attributeReport', 'readResponse'],
convert: (model, msg, publish, options, meta) => {
if (msg.data.hasOwnProperty('onOff')) {
const endpointName = utils.getKey(model.endpoint(meta.device), msg.endpoint.ID);
return {[`state_${endpointName}`]: msg.data['onOff'] === 1 ? 'ON' : 'OFF'};
}
},
} satisfies Fz.Converter,
};

const definitions: Definition[] = [
{
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_dd8wwzcy'}],
fingerprint: tuya.fingerprint('TS011F', ['_TZ3000_8nyaanzb', '_TZ3000_dd8wwzcy']),
model: 'MG-AUZG01',
vendor: 'MakeGood',
description: 'Double Zigbee power point',
fromZigbee: [fzLocal.MGAUZG01_on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report],
toZigbee: [tz.on_off],
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.power(), e.current(), e.voltage(),
e.energy()],
extend: tuya.extend.switch({powerOutageMemory: true, indicatorMode: true, endpoints: ['l1', 'l2']}),
meta: {multiEndpointSkip: ['power', 'current', 'voltage', 'energy']},
endpoint: (device) => {
return {'l1': 1, 'l2': 2};
},
Expand Down
15 changes: 15 additions & 0 deletions src/devices/sonoff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as reporting from '../lib/reporting';
import extend from '../lib/extend';
import {binary, numeric} from '../lib/modernExtend';
import {Definition, Fz, KeyValue} from '../lib/types';
import {onOff} from '../lib/modernExtend';

const e = exposes.presets;
const ea = exposes.access;
Expand Down Expand Up @@ -464,6 +465,20 @@ const definitions: Definition[] = [
await endpoint.read(0xFC11, [0x0000, 0x6000, 0x6002, 0x6003, 0x6004, 0x6005, 0x6006, 0x6007]);
},
},
{
zigbeeModel: ['S60ZBTPF'],
model: 'S60ZBTPF',
vendor: 'SONOFF',
description: 'Zigbee smart plug',
extend: [onOff()],
},
{
zigbeeModel: ['S60ZBTPG'],
model: 'S60ZBTPG',
vendor: 'SONOFF',
description: 'Zigbee smart plug',
extend: [onOff()],
},
];

export default definitions;
Expand Down
28 changes: 28 additions & 0 deletions src/devices/sunricher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,34 @@ const definitions: Definition[] = [
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
},
},
{
fingerprint: [{modelID: 'ON/OFF(2CH)', softwareBuildID: '2.9.2_r54'}],
model: 'SR-ZG9101SAC-HP-SWITCH-2CH',
vendor: 'Sunricher',
description: 'Zigbee 2 channel switch',
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.power_on_behavior, fz.ignore_genOta],
toZigbee: [tz.on_off, tz.power_on_behavior],
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.power(), e.current(),
e.voltage(), e.energy(), e.power_on_behavior(['off', 'on', 'previous'])],
endpoint: (device) => {
return {'l1': 1, 'l2': 2};
},
meta: {multiEndpoint: true},
configure: async (device, coordinatorEndpoint, logger) => {
const endpoint1 = device.getEndpoint(1);
const endpoint2 = device.getEndpoint(2);
await reporting.bind(endpoint1, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
await reporting.bind(endpoint2, coordinatorEndpoint, ['genOnOff']);
await reporting.onOff(endpoint1);
await reporting.onOff(endpoint2);
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint1);
await reporting.activePower(endpoint1);
await reporting.rmsCurrent(endpoint1, {min: 10, change: 10});
await reporting.rmsVoltage(endpoint1, {min: 10});
await reporting.readMeteringMultiplierDivisor(endpoint1);
await reporting.currentSummDelivered(endpoint1);
},
},
{
zigbeeModel: ['HK-ZD-CCT-A'],
model: 'HK-ZD-CCT-A',
Expand Down
12 changes: 7 additions & 5 deletions src/devices/tuya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3551,21 +3551,23 @@ const definitions: Definition[] = [
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [tuya.exposes.switch(), e.ac_frequency(), e.energy(), e.power(), e.power_factor(), e.voltage(), e.current(),
e.produced_energy()],
e.produced_energy(), e.power_reactive(),
e.numeric('energy_reactive', ea.STATE).withUnit('kVArh').withDescription('Sum of reactive energy'),
e.numeric('total_energy', ea.STATE).withUnit('kWh').withDescription('Total consumed and produced energy')],
meta: {
tuyaDatapoints: [
[1, 'energy', tuya.valueConverter.divideBy100],
[6, null, tuya.valueConverter.phaseVariant1], // voltage and current
[16, 'state', tuya.valueConverter.onOff],
[101, 'total_energy', tuya.valueConverter.divideBy100], // total energy produced + consumed
[102, 'produced_energy', tuya.valueConverter.divideBy100],
[103, 'power', tuya.valueConverter.raw],
[105, 'ac_frequency', tuya.valueConverter.divideBy100],
[109, 'energy_reactive', tuya.valueConverter.divideBy100], // reactive energy in VArh
[110, 'power_reactive', tuya.valueConverter.raw], // reactive power
[111, 'power_factor', tuya.valueConverter.divideBy10],
// Ignored for now; we don't know what the values mean
[109, null, null], // reactive_power in VArh, ignored for now
[101, null, null], // total active power (translated from chinese) - same as energy dp 1??
[9, null, null], // Fault - we don't know the possible values here
[110, null, null], // total reactive power (translated from chinese) - value is 0.03kvar, we already have kvarh on dp 109
[17, null, null], // Alarm set1 - value seems garbage "AAAAAAAAAAAAAABkAAEOAACqAAAAAAAKAAAAAAAA"
[18, null, null], // 18 - Alarm set2 - value seems garbage "AAUAZAAFAB4APAAAAAAAAAA="
],
Expand Down Expand Up @@ -5730,7 +5732,7 @@ const definitions: Definition[] = [
{
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_bcusnqt8'}],
model: 'SPM01-D2TZ',
vendor: 'Yagusmart',
vendor: 'Zemismart',
description: 'Smart energy monitor for 1P+N system',
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
Expand Down
14 changes: 8 additions & 6 deletions src/devices/xiaomi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1093,8 +1093,9 @@ const definitions: Definition[] = [
description: 'Aqara smart wall switch (no neutral, single rocker)',
fromZigbee: [fz.on_off, fz.xiaomi_multistate_action, xiaomi.fromZigbee.aqara_opple],
toZigbee: [tz.on_off, tz.xiaomi_switch_operation_mode_opple,
tz.xiaomi_flip_indicator_light, tz.aqara_switch_mode_switch],
exposes: [e.switch(), e.action(['single', 'double']), e.flip_indicator_light(),
tz.xiaomi_flip_indicator_light, tz.aqara_switch_mode_switch, tz.xiaomi_switch_power_outage_memory],
exposes: [e.switch(), e.action(['single', 'double']),
e.flip_indicator_light(), e.power_outage_memory(),
e.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']).withDescription('Decoupled mode'),
e.enum('mode_switch', ea.ALL, ['anti_flicker_mode', 'quick_mode'])
.withDescription('Anti flicker mode can be used to solve blinking issues of some lights.' +
Expand Down Expand Up @@ -2429,7 +2430,8 @@ const definitions: Definition[] = [
exposes: [
e.battery(), e.device_temperature(), e.vibration(), e.action(['vibration', 'tilt', 'drop']),
e.numeric('strength', ea.STATE), e.enum('sensitivity', ea.STATE_SET, ['low', 'medium', 'high']),
e.angle_axis('angle_x'), e.angle_axis('angle_y'), e.angle_axis('angle_z'), e.battery_voltage(), e.power_outage_count(false),
e.angle_axis('angle_x'), e.angle_axis('angle_y'), e.angle_axis('angle_z'),
e.x_axis(), e.y_axis(), e.z_axis(), e.battery_voltage(), e.power_outage_count(false),
],
},
{
Expand Down Expand Up @@ -2480,7 +2482,7 @@ const definitions: Definition[] = [
{
zigbeeModel: ['lumi.curtain.vagl02'],
model: 'ZNGZDJ16LM',
description: 'Aqara roller shade motor',
description: 'Aqara roller shade motor T1C',
vendor: 'Xiaomi',
fromZigbee: [xiaomi.fromZigbee.xiaomi_basic, fz.xiaomi_curtain_position, fz.xiaomi_curtain_position_tilt],
toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_options],
Expand Down Expand Up @@ -2662,8 +2664,8 @@ const definitions: Definition[] = [
xiaomiAction({postfixWithEndpointName: true}),
binary({
name: 'interlock',
valueOn: ['ON', true],
valueOff: ['OFF', false],
valueOn: ['ON', 1],
valueOff: ['OFF', 0],
cluster: 'aqaraOpple',
attribute: {id: 0x02d0, type: 0x10},
description: 'Enabling prevents both relays being on at the same time (Interlock)',
Expand Down

0 comments on commit 4f8df9d

Please sign in to comment.