Compare commits

...
50 Commits
Author SHA1 Message Date
Koen Kanters 3046680f61 1.13.1 2020-05-20 16:52:20 +02:00
Koen Kanters f206945506 Undev 2020-05-20 16:52:04 +02:00
Koen Kanters 2e96c8b03a Update converters 2020-05-20 16:51:11 +02:00
Koen Kanters 43699e133a Update converters. 2020-05-19 20:02:26 +02:00
Ryan Kim(True-World) a293b665b4 ADD DOWON_NEW_SW (#3570)
'PM-S140-ZB': [cfg.switch],
    'PM-S240-ZB': [switchEndpoint('top'), switchEndpoint('bottom')],
    'PM-S340-ZB': [switchEndpoint('top'), switchEndpoint('center'), switchEndpoint('bottom')],
2020-05-19 19:50:24 +02:00
Koen Kanters ad9421a9b0 Update converters. 2020-05-18 18:59:15 +02:00
Koen Kanters 134f67134b Update herdsman 2020-05-17 19:11:36 +02:00
Koen Kanters c7fddbc6e3 Fix devices not discovered in Home Assistant when repaired. https://github.com/home-assistant/core/issues/35684 2020-05-17 13:45:11 +02:00
Koen Kanters 29e5b9682c Update herdsman. 2020-05-17 13:44:02 +02:00
John Doe 33bed2bbfb Add more enpoins names for validation (#3552) 2020-05-15 16:54:36 +02:00
Koen Kanters 528539214c Also respect device_options for Home Assistant device specific configuration. #3541 2020-05-14 19:03:54 +02:00
Koen Kanters 855e9e0eb1 Don't add lastSeen to state. #3545 2020-05-14 18:47:27 +02:00
Michael Barrett 845bed4e11 add energy sensor for salus SP600 (#3551) 2020-05-14 18:39:48 +02:00
Michael Barrett 8e49dab722 add energy sensor for GP-WOU019BBDWG (#3550)
Simple metering support added for device in https://github.com/Koenkk/zigbee-herdsman-converters/pull/1234
2020-05-14 18:39:30 +02:00
kjkim74andKyungJong Kim 9a28f116b1 add support ECW-100-A03 (#3538)
Co-authored-by: KyungJong Kim <kyungjong74@gmail.com>
2020-05-12 17:57:08 +02:00
Koen Kanters cb64a865d9 Add requested_brightness_level and requested_brightness_percent Home Assistant sensor for IKEA E1745. #3535 2020-05-12 17:53:45 +02:00
Koen Kanters 520f59f47c Update converters 2020-05-11 18:35:45 +02:00
relaystarandTom Seeley c88666bde7 adding RS 229 T (#3527)
Co-authored-by: Tom Seeley <tom@tomseeley.co.uk>
2020-05-11 17:46:15 +02:00
Jussi Heikkilä 24a85abcd8 GL-C-008-2ID: White endpoint color temp control in Home Assistant (#3526) 2020-05-11 17:31:33 +02:00
hamsandoandKoen Kanters 8929544a12 Added ZBHT-1 (#3522)
* Added ZBHT-1

* Update homeassistant.js

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2020-05-11 17:12:16 +02:00
Koen Kanters fed84cfd5e Update converters. 2020-05-09 16:32:24 +02:00
Koen Kanters 739e6fb66b Update converters. 2020-05-09 16:10:31 +02:00
Koen Kanters 2a6659582b Update herdsman. 2020-05-08 20:29:32 +02:00
Koen Kanters 3f8371bef2 Update azure-pipelines.yaml 2020-05-08 17:05:20 +02:00
Koen Kanters 3d79688ffd Update azure-pipelines.yaml 2020-05-08 16:50:46 +02:00
Koen Kanters 3795562383 More new api stuff. https://github.com/Koenkk/zigbee2mqtt/issues/3281 2020-05-07 19:41:03 +02:00
Koen Kanters f816c8e740 Update converters. 2020-05-07 19:38:01 +02:00
nukusinji b2331da671 Update homeassistant.js (#3506)
Add Support TS0601
2020-05-07 19:32:26 +02:00
Koen Kanters e7e752a032 Dont log No converter available for.. on genTime messages. #3503 2020-05-07 18:01:09 +02:00
RicoGeandKoen Kanters fe0919d02a Added Linkind Door/Window Sensor Homeassistant config (#3500)
* Added Linkind Door/Window Sensor Homeassistant config

* Update homeassistant.js

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2020-05-06 20:01:06 +02:00
Koen Kanters 5aedf6b2ee Fix lint 2020-05-05 13:43:37 +02:00
Koen Kanters 5244fa0ed8 Update herdsman and converters. 2020-05-05 10:42:40 +02:00
Koen Kanters 856ecf47f1 Start on new API implementation. #3281 2020-05-04 20:06:50 +02:00
Koen Kanters 772f6c0bde Update converters. 2020-05-04 15:11:17 +02:00
Arno Moonen ff61695355 Fix Home Assistant discovery for GL-FL-004TZS. See Koenkk/zigbee2mqtt#3480 (#3484) 2020-05-04 11:33:58 +02:00
Niall McAndrew 07446ce1c1 Add temp and consumption to ZNCZ02LM (#3476) 2020-05-04 11:21:49 +02:00
dramamoose 20df5e5639 Add AE 260 to homeassistant.js (#3473) 2020-05-02 13:56:16 +02:00
presslab-us 7ae77ea528 Fixes for homeassistant thermostatHeatCool (#3466)
Remove 'auto' mode for 3157100 thermostat
unit_of_measurement in JSON should be temperature_unit
2020-05-02 13:47:02 +02:00
presslab-us bf1111edcb Support leakSMART water leak sensor (#3465) 2020-05-02 13:44:36 +02:00
Markus Pfeiffer 4c57323eae Add Dresden ballast Homeassistant companion (#3452) 2020-05-02 13:33:54 +02:00
Koen Kanters 90d8326e0c Update herdsman. 2020-05-02 11:33:23 +02:00
Koen Kanters e792f8bc8c Prevent sending Home Assistant discovery messages when not connected to MQTT yet. #3451 2020-04-30 19:06:17 +02:00
Igor Gocalinski a12d9fb73e Add temp sensor for QBKG11LM switch. (#3458)
Xiaomi Wired Single Switch QBKG11LM does support temperature readout
2020-04-30 18:41:35 +02:00
swissbyteandKoen Kanters cb47c12b55 Added new device DTB-ED2004-012 and added new cfg light_switch (#3439)
* added new device and added new cfg light_switch

* Added new device DTB-ED2004-012 and added new cfg light_switch

* added cfg.switch to generic ED2004-012

* Update homeassistant.js

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2020-04-30 18:39:58 +02:00
Koen Kanters 26e2757df6 Update converters. 2020-04-29 21:44:26 +02:00
Koen Kanters dabc944cd3 CC2530.router: state -> led. https://github.com/Koenkk/zigbee2mqtt/issues/3414 2020-04-29 21:27:58 +02:00
575e6fd4a3 3321 fixes (#3434)
* Add home assistant mapping for hive MOT003

* fix pipeline

* remove garbage

* Added 3321 battery sensor

* Update homeassistant.js

Co-authored-by: Iain Matchett <iain.matchett@beeksfx.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2020-04-29 21:18:30 +02:00
matchett808-ghandIain Matchett 305cb259b3 Add home assistant mapping for hive MOT003 (#3429)
* Add home assistant mapping for hive MOT003

* fix pipeline

* remove garbage

Co-authored-by: Iain Matchett <iain.matchett@beeksfx.com>
2020-04-29 17:36:49 +02:00
Jose Luis PedrosaandKoen Kanters 04bd928f3a Add support to home assistant for ZL1000700-22-EU-V1A02 (#3448)
* Add support to home assistant for ZL1000700-22-EU-V1A02 + missing devices

* Update homeassistant.js

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2020-04-29 17:27:16 +02:00
Koen Kanters e0ba80249c Dev 2020-04-29 17:09:38 +02:00
12 changed files with 1243 additions and 1918 deletions
+7 -9
View File
@@ -76,15 +76,13 @@ steps:
displayName: 'Docker build release'
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'), ne(variables['Build.Reason'], 'PullRequest'))
# Trigger downstream
# Trigger Home Assistant Zigbee2mqtt addon build
- bash: |
BODY="{\"request\": {\"branch\": \"master\"}}"
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Travis-API-Version: 3" \
-H "Authorization: token $(TRAVIS_TOKEN)" \
-d "$BODY" \
"https://api.travis-ci.org/repo/danielwelch%2Fhassio-zigbee2mqtt/requests"
curl -s \
--request POST \
--header "Content-Type: application/json" \
--data '{"definition": {"id": 1}}' \
-u "$(HASSIO_TRIGGER_SECRET)" \
"https://dev.azure.com/danielwelch2101/hassio-zigbee2mqtt/_apis/build/builds?api-version=5.1"
displayName: 'Trigger Hass.io build'
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/dev'), ne(variables['Build.Reason'], 'PullRequest'))
+8 -6
View File
@@ -19,6 +19,7 @@ const ExtensionHomeAssistant = require('./extension/homeassistant');
const ExtensionConfigure = require('./extension/configure');
const ExtensionDeviceGroupMembership = require('./extension/legacy/deviceGroupMembership');
const ExtensionBridgeLegacy = require('./extension/legacy/bridgeLegacy');
// const ExtensionBridge = require('./extension/bridge');
const ExtensionGroups = require('./extension/groups');
const ExtensionAvailability = require('./extension/availability');
const ExtensionBind = require('./extension/bind');
@@ -48,6 +49,7 @@ class Controller {
new ExtensionBind(...args),
new ExtensionOnEvent(...args),
new ExtensionOTAUpdate(...args),
// new ExtensionBridge(...args),
];
/* istanbul ignore else */
@@ -249,12 +251,6 @@ class Controller {
return;
}
const isDevice = resolvedEntity.type === 'device';
if (isDevice && settings.get().advanced.last_seen !== 'disable' && resolvedEntity.device.lastSeen) {
payload.last_seen = utils.formatDate(resolvedEntity.device.lastSeen, settings.get().advanced.last_seen);
}
let messagePayload = {...payload};
const currentState = this.state.exists(resolvedEntity.settings.ID) ?
this.state.get(resolvedEntity.settings.ID) : {};
@@ -279,6 +275,7 @@ class Controller {
options.properties = {messageExpiryInterval: retention};
}
const isDevice = resolvedEntity.type === 'device';
if (isDevice && settings.get().mqtt.include_device_information) {
const attributes = [
'ieeeAddr', 'networkAddress', 'type', 'manufacturerID', 'manufacturerName', 'powerSource',
@@ -293,6 +290,11 @@ class Controller {
attributes.forEach((a) => messagePayload.device[a] = resolvedEntity.device[a]);
}
const lastSeen = settings.get().advanced.last_seen;
if (isDevice && lastSeen !== 'disable' && resolvedEntity.device.lastSeen) {
messagePayload.last_seen = utils.formatDate(resolvedEntity.device.lastSeen, lastSeen);
}
// filter mqtt message attributes
if (deviceOptions.filtered_attributes) {
deviceOptions.filtered_attributes.forEach((a) => delete messagePayload[a]);
+212
View File
@@ -0,0 +1,212 @@
/* istanbul ignore file newApi */
const logger = require('../util/logger');
const utils = require('../util/utils');
const Extension = require('./extension');
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
const settings = require('../util/settings');
const requestRegex = new RegExp(`${settings.get().mqtt.base_topic}/bridge/request/(.*)`);
class BridgeLegacy extends Extension {
constructor(zigbee, mqtt, state, publishEntityState, eventBus) {
super(zigbee, mqtt, state, publishEntityState, eventBus);
this.requestLookup = {
'permitjoin': this.requestPermitJoin.bind(this),
'device/remove': this.deviceRemove.bind(this),
'device/forceremove': this.deviceForceRemove.bind(this),
'device/ban': this.deviceBan.bind(this),
'group/remove': this.groupRemove.bind(this),
};
}
async onMQTTConnected() {
this.mqtt.subscribe(`${settings.get().mqtt.base_topic}/bridge/request/+`);
await this.publishInfo();
await this.publishDevices();
await this.publishGroups();
}
async onMQTTMessage(topic, message) {
const match = topic.match(requestRegex);
if (match && this.requestLookup[match[1].toLowerCase()]) {
message = JSON.parse(message);
try {
const response = await this.requestLookup[match[1].toLowerCase()](message);
await this.mqtt.publish(`bridge/response/${match[1]}`, JSON.stringify(response));
} catch (error) {
logger.error(`Request '${topic}' failed with error: '${error.message}'`);
const response = utils.getResponse(message, {}, error.message);
await this.mqtt.publish(`bridge/response/${match[1]}`, JSON.stringify(response));
}
}
}
async onZigbeeEvent(type, data, resolvedEntity) {
if (['deviceJoined', 'deviceLeave', 'deviceInterview'].includes(type)) {
let payload;
const ieeeAddress = data.device ? data.device.ieeeAddr : data.ieeeAddr;
if (type === 'deviceJoined') payload = {friendlyName: resolvedEntity.settings.friendlyName, ieeeAddress};
else if (type === 'deviceInterview') {
payload = {friendlyName: resolvedEntity.settings.friendlyName, status: data.status, ieeeAddress};
if (data.status === 'successful') {
payload.supported = !!resolvedEntity.definition;
payload.definition = resolvedEntity.definition ? {
model: resolvedEntity.definition.model,
vendor: resolvedEntity.definition.vendor,
description: resolvedEntity.definition.description,
supports: resolvedEntity.definition.supports,
} : null;
}
} else payload = {ieeeAddress}; // deviceLeave
await this.mqtt.publish('bridge/event', JSON.stringify({type, data: payload}), {retain: false, qos: 0});
}
if ('deviceLeave' === type || ('deviceInterview' === type && data.status !== 'started')) {
await this.publishDevices();
}
}
/**
* Requests
*/
async deviceRemove(message) {
return this.removeForceRemoveOrBanEntity('remove', 'device', message);
}
async deviceForceRemove(message) {
return this.removeForceRemoveOrBanEntity('force_remove', 'device', message);
}
async deviceBan(message) {
return this.removeForceRemoveOrBanEntity('ban', 'device', message);
}
async groupRemove(message) {
return this.removeForceRemoveOrBanEntity('remove', 'group', message);
}
async requestPermitJoin(message) {
const value = typeof message === 'object' ? message.value : message;
await this.zigbee.permitJoin(value);
await this.publishInfo();
return utils.getResponse(message, {value: value}, null);
}
/**
* Utils
*/
async removeForceRemoveOrBanEntity(action, entityType, message) {
const ID = typeof message === 'object' ? message.ID : message.trim();
const entity = this.zigbee.resolveEntity(ID);
if (!entity || entity.type !== entityType) {
throw new Error(`${ID} is not a ${entityType}`);
}
const lookup = {
ban: ['banned', 'Banning', 'ban'],
force_remove: ['force_removed', 'Force removing', 'force remove'],
remove: ['removed', 'Removing', 'remove'],
};
try {
logger.info(`${lookup[action][1]} '${entity.settings.friendlyName}'`);
if (entity.type === 'device') {
if (action === 'ban') {
settings.banDevice(entity.settings.ID);
}
action === 'force_remove' ?
await entity.device.removeFromDatabase() : await entity.device.removeFromNetwork();
} else {
await entity.group.removeFromDatabase();
}
// Fire event
if (entity.type === 'device') {
this.eventBus.emit('deviceRemoved', {device: entity.device});
}
// Remove from configuration.yaml
entity.type === 'device' ?
settings.removeDevice(entity.settings.ID) : settings.removeGroup(entity.settings.ID);
// Remove from state
this.state.remove(entity.settings.ID);
logger.info(`Successfully ${lookup[action][0]} ${entity.settings.friendlyName}`);
entity.type === 'device' ? this.publishDevices() : this.publishGroups();
return utils.getResponse(message, {ID}, null);
} catch (error) {
throw new Error(`Failed to ${lookup[action][2]} ${entity.settings.friendlyName} (${error})`);
}
}
async publishInfo() {
const info = await utils.getZigbee2mqttVersion();
const coordinator = await this.zigbee.getCoordinatorVersion();
const payload = {
version: info.version,
commit: info.commitHash,
coordinator,
logLevel: logger.getLevel(),
permitJoin: await this.zigbee.getPermitJoin(),
};
await this.mqtt.publish('bridge/info', JSON.stringify(payload), {retain: true, qos: 0});
}
async publishDevices(topic, message) {
const devices = this.zigbee.getClients().map((device) => {
const definition = zigbeeHerdsmanConverters.findByDevice(device);
const resolved = this.zigbee.resolveEntity(device);
const definitionPayload = definition ? {
model: definition.model,
vendor: definition.vendor,
description: definition.description,
supports: definition.supports,
} : null;
return {
ieeeAddress: device.ieeeAddr,
type: device.type,
networkAddress: device.networkAddress,
supported: !!definition,
friendlyName: resolved.settings.friendlyName,
definition: definitionPayload,
powerSource: device.powerSource,
softwareBuildID: device.softwareBuildID,
dateCode: device.dateCode,
interviewing: device.interviewing,
interviewCompleted: device.interviewCompleted,
};
});
await this.mqtt.publish('bridge/devices', JSON.stringify(devices), {retain: true, qos: 0});
}
async publishGroups(topic, message) {
const groups = this.zigbee.getGroups().map((group) => {
const resolved = this.zigbee.resolveEntity(group);
return {
ID: group.groupID,
friendlyName: resolved.settings.friendlyName,
members: group.members.map((m) => {
return {
ieeeAddress: m.deviceIeeeAddress,
endpoint: m.ID,
};
}),
};
});
await this.mqtt.publish('bridge/groups', JSON.stringify(groups), {retain: true, qos: 0});
}
}
module.exports = BridgeLegacy;
+99 -26
View File
@@ -95,14 +95,14 @@ const cfg = {
device_class: 'safety',
},
},
'binary_sensor_router': {
'binary_sensor_led': {
type: 'binary_sensor',
object_id: 'router',
object_id: 'led',
discovery_payload: {
payload_on: true,
payload_off: false,
value_template: '{{ value_json.state }}',
device_class: 'connectivity',
value_template: '{{ value_json.led }}',
device_class: 'light',
},
},
'binary_sensor_battery_low': {
@@ -406,6 +406,22 @@ const cfg = {
icon: 'mdi:weight',
},
},
'sensor_requested_brightness_level': {
type: 'sensor',
object_id: 'requested_brightness_level',
discovery_payload: {
value_template: '{{ value_json.requested_brightness_level }}',
icon: 'mdi:brightness-5',
},
},
'sensor_requested_brightness_percent': {
type: 'sensor',
object_id: 'requested_brightness_percent',
discovery_payload: {
value_template: '{{ value_json.requested_brightness_percent }}',
icon: 'mdi:brightness-5',
},
},
// Light
'light_brightness_colorxy_white': {
@@ -417,6 +433,7 @@ const cfg = {
white_value: true,
schema: 'json',
command_topic: true,
brightness_scale: 254,
},
},
'light_brightness_colortemp_colorxy_white': {
@@ -429,6 +446,7 @@ const cfg = {
schema: 'json',
command_topic: true,
color_temp: true,
brightness_scale: 254,
},
},
'light_brightness_colortemp_colorxy': {
@@ -440,6 +458,7 @@ const cfg = {
xy: true,
schema: 'json',
command_topic: true,
brightness_scale: 254,
},
},
'light_brightness_colorxy': {
@@ -450,6 +469,7 @@ const cfg = {
xy: true,
schema: 'json',
command_topic: true,
brightness_scale: 254,
},
},
'light_brightness_colortemp_colorhs': {
@@ -461,6 +481,7 @@ const cfg = {
hs: true,
schema: 'json',
command_topic: true,
brightness_scale: 254,
},
},
'light_brightness_colortemp': {
@@ -471,6 +492,7 @@ const cfg = {
color_temp: true,
schema: 'json',
command_topic: true,
brightness_scale: 254,
},
},
'light_brightness': {
@@ -480,6 +502,7 @@ const cfg = {
brightness: true,
schema: 'json',
command_topic: true,
brightness_scale: 254,
},
},
@@ -678,16 +701,16 @@ const thermostat = (minTemp=7, maxTemp=30, temperatureStateProperty='occupied_he
};
};
const thermostatHeatCool = /* istanbul ignore next */ (minTemp=7, maxTemp=30, tempStep=0.5, fanModes=[]) => {
const thermostatHeatCool = /* istanbul ignore next */ (minTemp=7, maxTemp=30, tempStep=0.5, opModes, fanModes=[]) => {
return {
type: 'climate',
object_id: 'climate',
discovery_payload: {
state_topic: false,
unit_of_measurement: '°C',
temperature_unit: 'C',
min_temp: `${minTemp}`,
max_temp: `${maxTemp}`,
modes: ['off', 'auto', 'heat', 'cool'],
modes: opModes,
mode_state_topic: true,
mode_state_template: '{{ value_json.system_mode }}',
mode_command_topic: true,
@@ -730,7 +753,7 @@ const mapping = {
'MCCGQ11LM': [cfg.binary_sensor_contact, cfg.sensor_battery],
'SJCGQ11LM': [cfg.binary_sensor_water_leak, cfg.sensor_battery],
'MFKZQ01LM': [cfg.sensor_action, cfg.sensor_battery],
'ZNCZ02LM': [cfg.switch, cfg.sensor_power],
'ZNCZ02LM': [cfg.switch, cfg.sensor_power, cfg.sensor_temperature, cfg.sensor_consumption],
'QBCZ11LM': [cfg.switch, cfg.sensor_power],
'LED1545G12': [cfg.light_brightness_colortemp],
'LED1623G12': [cfg.light_brightness],
@@ -746,7 +769,7 @@ const mapping = {
'JTYJ-GD-01LM/BW': [cfg.binary_sensor_smoke, cfg.sensor_battery, cfg.sensor_sensitivity, cfg.sensor_smoke_density],
'PLUG EDP RE:DY': [cfg.switch, cfg.sensor_power],
'SWITCH EDP RE:DY': [cfg.switch],
'CC2530.ROUTER': [cfg.binary_sensor_router],
'CC2530.ROUTER': [cfg.binary_sensor_led],
'AA70155': [cfg.light_brightness_colortemp],
'A9A19A60WESDZ02': [cfg.light_brightness_colortemp],
'4058075816718': [cfg.light_brightness_colortemp_colorxy],
@@ -793,8 +816,9 @@ const mapping = {
'SL 110 N': [cfg.light_brightness],
'SL 110 M': [cfg.light_brightness],
'SL 110 W': [cfg.light_brightness],
'AE 260': [cfg.light_brightness],
'AA68199': [cfg.light_brightness_colortemp],
'QBKG11LM': [cfg.switch, cfg.sensor_power, cfg.sensor_click],
'QBKG11LM': [cfg.switch, cfg.sensor_power, cfg.sensor_click, cfg.sensor_temperature],
'QBKG12LM': [
switchEndpoint('left'), switchEndpoint('right'), cfg.sensor_power, cfg.sensor_click,
cfg.sensor_temperature,
@@ -858,7 +882,7 @@ const mapping = {
'7299355PH': [cfg.light_brightness_colorxy],
'45857GE': [cfg.light_brightness],
'A6121': [cfg.sensor_lock],
'433714': [cfg.light_brightness],
'433714': [cfg.light_brightness_colortemp],
'3261030P7': [cfg.light_brightness_colortemp],
'3216431P5': [cfg.light_brightness_colortemp],
'DJT11LM': [cfg.sensor_action, cfg.sensor_battery, cfg.sensor_sensitivity, cfg.sensor_strength],
@@ -886,7 +910,8 @@ const mapping = {
'3216331P5': [cfg.light_brightness_colortemp],
'AC08562': [cfg.light_brightness],
'900008-WW': [cfg.light_brightness],
'Mega23M12': [cfg.light_brightness_colortemp_colorxy],
'Mega23M12': [lightEndpoint('light_brightness_colortemp_colorxy', 'rgb'),
lightEndpoint('light_brightness', 'white')],
'PSS-23ZBS': [cfg.switch],
'HS1SA-M': [cfg.binary_sensor_smoke, cfg.binary_sensor_battery_low],
'Z01-A19NAE26': [cfg.light_brightness_colortemp],
@@ -904,13 +929,14 @@ const mapping = {
'HS1-WL-E': [cfg.binary_sensor_water_leak],
'421786': [cfg.light_brightness],
'ICZB-IW11D': [cfg.light_brightness],
'3321-S': [cfg.binary_sensor_contact, cfg.sensor_temperature],
'3321-S': [cfg.binary_sensor_contact, cfg.sensor_temperature, cfg.sensor_battery],
'ZPIR-8000': [cfg.binary_sensor_occupancy, cfg.sensor_battery],
'ZCTS-808': [cfg.binary_sensor_contact, cfg.sensor_battery],
'ZNLDP12LM': [cfg.light_brightness_colortemp],
'D1821': [cfg.light_brightness_colortemp_colorxy],
'ZNCLDJ11LM': [cfg.cover_position, cfg.sensor_cover],
'owvfni3': [cfg.cover_position],
'TS0601': [cfg.cover_position],
'LTFY004': [cfg.light_brightness_colorxy],
'GL-S-007Z': [cfg.light_brightness_colortemp_colorxy],
'3325-S': [cfg.sensor_temperature, cfg.binary_sensor_occupancy],
@@ -937,7 +963,11 @@ const mapping = {
'HGZB-07A': [cfg.light_brightness_colortemp_colorxy],
'E1524/E1810': [cfg.sensor_action, cfg.sensor_battery],
'GL-C-006': [cfg.light_brightness_colortemp],
'GL-C-007': [cfg.light_brightness_colorxy_white],
'GL-C-007-1ID': [cfg.light_brightness_colortemp_colorxy],
'GL-C-007-2ID': [lightEndpoint('light_brightness_colortemp_colorxy', 'rgb'),
lightEndpoint('light_brightness', 'white')],
'GL-C-008-2ID': [lightEndpoint('light_brightness_colorxy', 'rgb'),
lightEndpoint('light_brightness_colortemp', 'cct')],
'GL-C-007S': [cfg.light_brightness_colorxy_white],
'GL-C-007/GL-C-008': [cfg.light_brightness_colortemp_colorxy_white],
'100.424.11': [cfg.light_brightness_colortemp],
@@ -950,7 +980,7 @@ const mapping = {
'GL-S-003Z': [cfg.light_brightness_colorxy_white],
'GL-S-005Z': [cfg.light_brightness_colortemp_colorxy],
'HS1DS-E': [cfg.binary_sensor_contact],
'SP600': [cfg.switch, cfg.sensor_power],
'SP600': [cfg.switch, cfg.sensor_power, cfg.sensor_energy],
'1613V': [cfg.switch, cfg.sensor_power],
'XVV-Mega23M12': [cfg.light_brightness_colortemp],
'GL-B-007Z': [cfg.light_brightness_colortemp_colorxy],
@@ -982,6 +1012,7 @@ const mapping = {
'HGZB-042': [switchEndpoint('top'), switchEndpoint('bottom')],
'HGZB-42': [switchEndpoint('top'), switchEndpoint('bottom')],
'GL-FL-004TZ': [cfg.light_brightness_colortemp_colorxy],
'GL-FL-004TZS': [cfg.light_brightness_colortemp_colorxy],
'IM6001-OTP05': [cfg.switch],
'SV01': [
cfg.cover_position, cfg.sensor_temperature, cfg.sensor_pressure,
@@ -998,7 +1029,10 @@ const mapping = {
cfg.sensor_local_temperature,
cfg.lock_keypad_lockout,
],
'E1525/E1745': [cfg.binary_sensor_occupancy, cfg.sensor_battery],
'E1525/E1745': [
cfg.binary_sensor_occupancy, cfg.sensor_battery, cfg.sensor_requested_brightness_level,
cfg.sensor_requested_brightness_percent,
],
'ZYCT-202': [cfg.sensor_action],
'GR-ZB01-W': [cfg.cover_position],
'4090531P7': [cfg.light_brightness_colortemp_colorxy],
@@ -1113,6 +1147,7 @@ const mapping = {
],
'HLC821-Z-SC': [cfg.light_brightness],
'RS 228 T': [cfg.light_brightness_colortemp],
'RS 229 T': [cfg.light_brightness_colortemp],
'67200BL': [cfg.switch],
'InstaRemote': [cfg.sensor_action],
'100.425.90': [cfg.switch],
@@ -1128,7 +1163,7 @@ const mapping = {
'ZigUP': [cfg.switch],
'YRD256HA20BP': [cfg.sensor_battery, cfg.lock],
'SZ-ESW01-AU': [cfg.sensor_power, cfg.switch],
'PSM-29ZBSR': [cfg.switch],
'PSM-29ZBSR': [cfg.switch, cfg.sensor_power],
'ZM350STW1TCF': [cfg.light_brightness_colortemp],
'M350STW1': [cfg.light_brightness],
'A806S-Q1R': [cfg.light_brightness],
@@ -1286,7 +1321,7 @@ const mapping = {
'ZM-CSW032-D': [cfg.cover_position],
'LH-32ZB': [cfg.sensor_humidity, cfg.sensor_temperature, cfg.sensor_battery],
'511.201': [cfg.light_brightness],
'ZNCLDJ12LM': [cfg.cover_position],
'ZNCLDJ12LM': [cfg.cover_position, cfg.sensor_battery],
'046677552343': [cfg.switch],
'3115331PH': [cfg.light_brightness_colortemp_colorxy],
'ZWLD-100': [cfg.binary_sensor_water_leak, cfg.binary_sensor_battery_low, cfg.sensor_battery],
@@ -1413,13 +1448,14 @@ const mapping = {
'1744130P7': [cfg.light_brightness_colortemp_colorxy],
'1743130P7': [cfg.light_brightness_colortemp_colorxy],
'100.110.51': [cfg.light_brightness_colortemp],
'ZL1000100-CCT-US-V1A02': [cfg.light_brightness],
'ZL1000100-CCT-US-V1A02': [cfg.light_brightness_colortemp],
'ZL1000701-27-EU-V1A02': [cfg.light_brightness],
'HGZB-DLC4-N12B': [cfg.light_brightness_colortemp_colorxy],
'U86KCJ-ZP': [cfg.sensor_action],
'HS1HT': [cfg.sensor_temperature, cfg.sensor_humidity, cfg.sensor_battery],
'HS2ESK-E': [cfg.switch, cfg.sensor_power],
'B01M7Y8BP9': [cfg.sensor_action],
'GP-WOU019BBDWG': [cfg.switch, cfg.sensor_power],
'GP-WOU019BBDWG': [cfg.switch, cfg.sensor_power, cfg.sensor_energy],
'AV2010/21A': [cfg.binary_sensor_battery_low, cfg.binary_sensor_contact, cfg.binary_sensor_tamper],
'AL-PIR02': [cfg.binary_sensor_occupancy, cfg.binary_sensor_tamper, cfg.sensor_battery],
'MKS-CM-W5': [
@@ -1489,6 +1525,9 @@ const mapping = {
'PM-S140-ZB': [cfg.switch],
'PM-S240-ZB': [switchEndpoint('top'), switchEndpoint('bottom')],
'PM-S340-ZB': [switchEndpoint('top'), switchEndpoint('center'), switchEndpoint('bottom')],
'PM-S140R-ZB': [cfg.switch],
'PM-S240R-ZB': [switchEndpoint('top'), switchEndpoint('bottom')],
'PM-S340R-ZB': [switchEndpoint('top'), switchEndpoint('center'), switchEndpoint('bottom')],
'U201DST600ZB': [cfg.light_brightness],
'U201SRY2KWZB': [cfg.switch],
'U202SRY2KWZB': [switchEndpoint('l1'), switchEndpoint('l2')],
@@ -1533,7 +1572,7 @@ const mapping = {
'E12-N1E': [cfg.light_brightness_colortemp_colorxy],
'4040B': [cfg.sensor_power, switchEndpoint('l1'), switchEndpoint('l2')],
'3460-L': [cfg.sensor_action, cfg.sensor_temperature, cfg.sensor_battery],
'3157100': [thermostatHeatCool(10, 30, 1, ['auto', 'on']), cfg.sensor_battery],
'3157100': [thermostatHeatCool(10, 30, 1, ['off', 'heat', 'cool'], ['auto', 'on']), cfg.sensor_battery],
'4257050-RZHAC': [cfg.switch, cfg.sensor_power],
'27087-03': [cfg.switch, cfg.sensor_battery],
'99140-002': [cfg.lock, cfg.sensor_battery],
@@ -1541,12 +1580,16 @@ const mapping = {
'GL-S-004ZS': [cfg.light_brightness_colortemp_colorxy],
'7121131PU': [cfg.light_brightness_colortemp_colorxy],
'RL804QZB': [switchEndpoint('l1'), switchEndpoint('l2'), switchEndpoint('l3')],
'RC-2000WH': [thermostatHeatCool(10, 30, 1, ['auto', 'on', 'smart'])],
'RC-2000WH': [thermostatHeatCool(10, 30, 1, ['off', 'auto', 'heat', 'cool'], ['auto', 'on', 'smart'])],
'TH1300ZB': [thermostat()],
'SP 220': [cfg.switch],
'511.040': [cfg.light_brightness_colortemp_colorxy],
'511.344': [cfg.sensor_battery, cfg.sensor_action, cfg.sensor_action_color, cfg.sensor_action_color_temperature],
'SMSZB-120': [cfg.binary_sensor_smoke, cfg.sensor_temperature, cfg.sensor_battery],
'MOT003': [
cfg.sensor_temperature, cfg.binary_sensor_occupancy, cfg.sensor_illuminance,
cfg.sensor_illuminance_lux, cfg.binary_sensor_battery_low, cfg.sensor_battery,
],
'HALIGHTDIMWWE14': [cfg.light_brightness],
'GreenPower_On_Off_Switch': [cfg.sensor_action],
'GreenPower_7': [cfg.sensor_action],
@@ -1573,7 +1616,7 @@ const mapping = {
'676-00301024955Z': [cfg.light_brightness],
'1743030P7': [cfg.light_brightness_colortemp_colorxy],
'XBee': [],
'ZL1000701-27-EU-V1A02': [cfg.light_brightness],
'ZBHT-1': [cfg.sensor_temperature, cfg.sensor_humidity, cfg.sensor_battery],
'rgbw2.zbee27': [cfg.light_brightness_colortemp_colorxy],
'MCLH-05': [cfg.binary_sensor_occupancy, cfg.sensor_battery],
'5045148P7': [cfg.light_brightness_colortemp_colorxy],
@@ -1587,8 +1630,37 @@ const mapping = {
'ZS1100400-IN-V1A02': [cfg.binary_sensor_occupancy, cfg.binary_sensor_battery_low],
'MCLH-08': [cfg.sensor_temperature, cfg.sensor_humidity, cfg.sensor_eco2, cfg.sensor_voc],
'GL-FL-005TZ': [cfg.light_brightness_colortemp_colorxy],
'ED2004-012': [],
'ED2004-012': [cfg.switch],
'ZG192910-4': [cfg.light_brightness_colortemp],
'SLT2': [],
'ZL1000700-22-EU-V1A02': [cfg.light_brightness],
'SLB2': [],
'8840100H': [cfg.binary_sensor_water_leak, cfg.sensor_temperature, cfg.sensor_battery],
'404037': [cfg.light_brightness_colortemp],
'9290022408': [cfg.switch],
'HGZB-14A': [cfg.binary_sensor_water_leak, cfg.sensor_battery],
'TERNCY-DC01': [cfg.sensor_temperature, cfg.binary_sensor_contact],
'ZS110050078': [cfg.binary_sensor_contact, cfg.binary_sensor_battery_low],
'HGZB-DLC4-N15B': [cfg.light_brightness_colortemp_colorxy],
'ECW-100-A03': [switchEndpoint('top'), switchEndpoint('center'), switchEndpoint('bottom')],
'4098430P7': [cfg.light_brightness_colortemp],
'PQC19-DY01': [cfg.light_brightness],
'DIYRuZ_FreePad': [cfg.sensor_action, cfg.sensor_battery],
'ST20': [cfg.sensor_temperature, cfg.sensor_humidity, cfg.sensor_battery],
'ST21': [cfg.sensor_temperature, cfg.sensor_humidity, cfg.sensor_battery],
'T30W3Z': [switchEndpoint('top'), switchEndpoint('center'), switchEndpoint('bottom')],
'T21W2Z': [switchEndpoint('top'), switchEndpoint('bottom')],
'T21W1Z': [cfg.switch],
'W40CZ': [cfg.cover_position],
'R11W2Z': [switchEndpoint('l1'), switchEndpoint('l2')],
'R20W2Z': [switchEndpoint('l1'), switchEndpoint('l2')],
'SW21': [cfg.binary_sensor_water_leak, cfg.binary_sensor_battery_low],
'SE21': [cfg.sensor_action],
'4052899926127': [cfg.light_brightness],
'GL-B-001ZS': [cfg.light_brightness_colortemp_colorxy],
'LH-990ZB': [cfg.binary_sensor_occupancy, cfg.binary_sensor_battery_low],
'HO-09ZB': [cfg.binary_sensor_contact, cfg.binary_sensor_battery_low],
'500.67': [cfg.sensor_action],
};
/**
@@ -1619,6 +1691,7 @@ class HomeAssistant extends Extension {
}
onDeviceRemoved(device) {
delete this.discovered[device.ieeeAddr];
const definition = zigbeeHerdsmanConverters.findByDevice(device);
if (definition) {
logger.info(`Clearing Home Assistant discovery topic for '${device.ieeeAddr}'`);
@@ -1766,7 +1839,7 @@ class HomeAssistant extends Extension {
discover(resolvedEntity, force=false) {
// Check if already discoverd and check if there are configs.
const {device, definition} = resolvedEntity;
const deviceSettings = resolvedEntity.settings;
const deviceSettings = {...settings.get().device_options, ...resolvedEntity.settings};
const discover = force || !this.discovered[device.ieeeAddr];
if (!discover || !device || !definition || !mapping[definition.model] || !deviceSettings ||
(deviceSettings.hasOwnProperty('homeassistant') && !deviceSettings.homeassistant)) {
@@ -1960,7 +2033,7 @@ class HomeAssistant extends Extension {
}
onZigbeeEvent(type, data, resolvedEntity) {
if (resolvedEntity && type !== 'deviceLeave') {
if (resolvedEntity && type !== 'deviceLeave' && this.mqtt.isConnected()) {
this.discover(resolvedEntity);
}
}
+1 -1
View File
@@ -191,7 +191,7 @@ class EntityPublish extends Extension {
const msg = result.state;
if (endpointName) {
for (const key of ['state', 'brightness']) {
for (const key of ['state', 'brightness', 'color', 'color_temp']) {
if (msg.hasOwnProperty(key)) {
msg[`${key}_${endpointName}`] = msg[key];
delete msg[key];
+1 -1
View File
@@ -107,7 +107,7 @@ class Receive extends Extension {
});
// Check if there is an available converter, genOta messages are not interesting.
if (!converters.length && data.cluster !== 'genOta') {
if (!converters.length && data.cluster !== 'genOta' && data.cluster !== 'genTime') {
logger.debug(
`No converter available for '${resolvedEntity.definition.model}' with cluster '${data.cluster}' ` +
`and type '${data.type}' and data '${JSON.stringify(data.data)}'`,
+5 -1
View File
@@ -95,11 +95,15 @@ class MQTT extends events.EventEmitter {
this.emit('message', {topic, message: message.toString()});
}
isConnected() {
return this.client && !this.client.reconnecting;
}
async publish(topic, payload, options, base=settings.get().mqtt.base_topic) {
topic = `${base}/${topic}`;
options = {qos: 0, retain: false, ...options};
if (!this.client || this.client.reconnecting) {
if (!this.isConnected()) {
logger.error(`Not connected to MQTT server!`);
logger.error(`Cannot send message: topic: '${topic}', payload: '${payload}`);
return;
+16 -1
View File
@@ -29,9 +29,13 @@ function toLocalISOString(dDate) {
const endpointNames = [
'left', 'right', 'center', 'bottom_left', 'bottom_right', 'default',
'top_left', 'top_right', 'white', 'rgb', 'system', 'top', 'bottom', 'center_left', 'center_right',
'top_left', 'top_right', 'white', 'rgb', 'cct', 'system', 'top', 'bottom', 'center_left', 'center_right',
'ep1', 'ep2', 'row_1', 'row_2', 'row_3', 'row_4', 'relay',
'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8',
'button_1', 'button_2', 'button_3', 'button_4', 'button_5',
'button_6', 'button_7', 'button_8', 'button_9', 'button_10',
'button_11', 'button_12', 'button_13', 'button_14', 'button_15',
'button_16', 'button_17', 'button_18', 'button_19', 'button_20',
];
function flatten(arr) {
@@ -120,6 +124,16 @@ function getObjectsProperty(objects, key, defaultValue) {
return defaultValue;
}
/* istanbul ignore next newApi */
function getResponse(request, data, error) {
const response = {data, status: error ? 'error' : 'ok'};
if (error) response.error = error;
if (typeof request === 'object' && request.hasOwnProperty('transaction')) {
response.transaction = request.transaction;
}
return response;
}
module.exports = {
millisecondsToSeconds: (milliseconds) => milliseconds / 1000,
secondsToMilliseconds: (seconds) => seconds * 1000,
@@ -136,4 +150,5 @@ module.exports = {
isBatteryPowered: (device) => device.powerSource && device.powerSource === 'Battery',
formatDate: (date, type) => formatDate(date, type),
equalsPartial,
getResponse,
};
+12 -2
View File
@@ -149,9 +149,11 @@ class Zigbee extends events.EventEmitter {
* }
*/
resolveEntity(key) {
/* istanbul ignore next newApi */
assert(
typeof key === 'string' || typeof key === 'number' ||
key.constructor.name === 'Device', `Wrong type '${typeof key}'`,
key.constructor.name === 'Device' || key.constructor.name === 'Group',
`Wrong type '${typeof key}'`,
);
if (typeof key === 'string' || typeof key === 'number') {
@@ -215,7 +217,7 @@ class Zigbee extends events.EventEmitter {
if (!group) group = this.createGroup(entity.ID);
return {type: 'group', group, settings: entity, name: entity.friendlyName};
}
} else {
} /* istanbul ignore else newApi */ else if (key.constructor.name === 'Device') {
const setting = settings.getEntity(key.ieeeAddr);
return {
type: 'device',
@@ -225,6 +227,14 @@ class Zigbee extends events.EventEmitter {
name: setting ? setting.friendlyName : (key.type === 'Coordinator' ? 'Coordinator' : key.ieeeAddr),
definition: zigbeeHerdsmanConverters.findByDevice(key),
};
} else { // Group
const setting = settings.getEntity(key.groupID);
return {
type: 'group',
group: key,
settings: setting,
name: setting.friendlyName,
};
}
}
+858 -1866
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "zigbee2mqtt",
"version": "1.13.0",
"version": "1.13.1",
"description": "Zigbee to MQTT bridge using Zigbee-herdsman",
"main": "index.js",
"repository": {
@@ -45,8 +45,8 @@
"rimraf": "*",
"semver": "*",
"winston": "*",
"zigbee-herdsman": "0.12.83",
"zigbee-herdsman-converters": "12.0.81"
"zigbee-herdsman": "0.12.90",
"zigbee-herdsman-converters": "12.0.92"
},
"devDependencies": {
"eslint": "*",
+21 -2
View File
@@ -1,6 +1,7 @@
const data = require('./stub/data');
const logger = require('./stub/logger');
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
const MQTT = require('./stub/mqtt');
const settings = require('../lib/util/settings');
const Controller = require('../lib/controller');
@@ -48,6 +49,8 @@ describe('Publish', () => {
Object.values(zigbeeHerdsman.groups).forEach((g) => {
g.command.mockClear();
});
zigbeeHerdsmanConverters.toZigbeeConverters.__clearStore__();
});
it('Should publish messages to zigbee devices', async () => {
@@ -586,6 +589,22 @@ describe('Publish', () => {
expect(endpoint.command.mock.calls[0]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 20, transtime: 200}, {}]);
});
it('Transition parameter should not influence brightness on state ON', async () => {
// https://github.com/Koenkk/zigbee2mqtt/issues/3563
const device = zigbeeHerdsman.devices.bulb_color;
const endpoint = device.getEndpoint(1);
await MQTT.events.message('zigbee2mqtt/bulb_color/set', JSON.stringify({"state": "ON", "brightness": 50}));
await flushPromises();
await MQTT.events.message('zigbee2mqtt/bulb_color/set', JSON.stringify({"state": "ON"}));
await flushPromises();
await MQTT.events.message('zigbee2mqtt/bulb_color/set', JSON.stringify({"state": "ON", "transition": 1}));
await flushPromises();
expect(endpoint.command).toHaveBeenCalledTimes(3);
expect(endpoint.command.mock.calls[0]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 50, transtime: 0}, {}]);
expect(endpoint.command.mock.calls[1]).toEqual(["genOnOff", "on", {}, {}]);
expect(endpoint.command.mock.calls[2]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 50, transtime: 10}, {}]);
});
it('Should use transition when color temp', async () => {
const device = zigbeeHerdsman.devices.bulb_color;
settings.set(['devices', device.ieeeAddr, 'transition'], 20);
@@ -719,7 +738,7 @@ describe('Publish', () => {
await MQTT.events.message('zigbee2mqtt/bulb_color/set', JSON.stringify(payload));
await flushPromises();
expect(endpoint.command).toHaveBeenCalledTimes(1);
expect(endpoint.command.mock.calls[0]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 255, transtime: 30}, {}]);
expect(endpoint.command.mock.calls[0]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 254, transtime: 30}, {}]);
});
it('Should turn device on with on/off with transition when transition 0 is provided', async () => {
@@ -729,7 +748,7 @@ describe('Publish', () => {
await MQTT.events.message('zigbee2mqtt/bulb_color/set', JSON.stringify(payload));
await flushPromises();
expect(endpoint.command).toHaveBeenCalledTimes(1);
expect(endpoint.command.mock.calls[0]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 255, transtime: 0}, {}]);
expect(endpoint.command.mock.calls[0]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 254, transtime: 0}, {}]);
});
it('Should turn device off with onOff on off with transition', async () => {