2019-09-09 10:48:09 -07:00
|
|
|
const data = require('./stub/data');
|
2019-01-08 11:00:47 -07:00
|
|
|
const settings = require('../lib/util/settings');
|
2019-09-09 10:48:09 -07:00
|
|
|
const logger = require('./stub/logger');
|
|
|
|
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
|
|
|
|
const flushPromises = () => new Promise(setImmediate);
|
|
|
|
const MQTT = require('./stub/mqtt');
|
|
|
|
const Controller = require('../lib/controller');
|
2018-11-16 12:23:11 -07:00
|
|
|
|
|
|
|
describe('HomeAssistant extension', () => {
|
2019-09-09 10:48:09 -07:00
|
|
|
beforeEach(async () => {
|
|
|
|
this.version = await require('../lib/util/utils').getZigbee2mqttVersion();
|
|
|
|
this.version = `Zigbee2mqtt ${this.version.version}`;
|
|
|
|
jest.useRealTimers();
|
|
|
|
data.writeDefaultConfiguration();
|
|
|
|
settings._reRead();
|
|
|
|
data.writeEmptyState();
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
settings.set(['homeassistant'], true);
|
2019-01-08 11:00:47 -07:00
|
|
|
});
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should have mapping for all devices supported by zigbee-herdsman-converters', () => {
|
2018-11-16 12:23:11 -07:00
|
|
|
const missing = [];
|
2019-09-09 10:48:09 -07:00
|
|
|
const HomeAssistant = require('../lib/extension/homeassistant');
|
2020-01-09 13:47:19 -07:00
|
|
|
const ha = new HomeAssistant(null, null, null, null, {on: () => {}});
|
2018-11-16 12:23:11 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
require('zigbee-herdsman-converters').devices.forEach((d) => {
|
|
|
|
if (!ha._getMapping()[d.model]) {
|
2018-11-16 12:23:11 -07:00
|
|
|
missing.push(d.model);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-03-09 14:12:10 -07:00
|
|
|
expect(missing).toHaveLength(0);
|
2019-09-09 10:48:09 -07:00
|
|
|
});
|
2019-01-08 11:00:47 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should discover devices', async () => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
2019-01-08 11:00:47 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
let payload;
|
|
|
|
await flushPromises();
|
2019-01-08 11:00:47 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '°C',
|
|
|
|
'device_class': 'temperature',
|
|
|
|
'value_template': '{{ value_json.temperature }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_temperature',
|
|
|
|
'unique_id': '0x0017880104e45522_temperature_zigbee2mqtt',
|
2019-01-08 11:00:47 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-01-08 11:00:47 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/temperature/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-01-08 11:00:47 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '%',
|
|
|
|
'device_class': 'humidity',
|
|
|
|
'value_template': '{{ value_json.humidity }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_humidity',
|
|
|
|
'unique_id': '0x0017880104e45522_humidity_zigbee2mqtt',
|
2019-01-08 11:00:47 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-01-08 11:00:47 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/humidity/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-01-08 11:00:47 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': 'hPa',
|
|
|
|
'device_class': 'pressure',
|
|
|
|
'value_template': '{{ value_json.pressure }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_pressure',
|
|
|
|
'unique_id': '0x0017880104e45522_pressure_zigbee2mqtt',
|
2019-01-08 11:00:47 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-01-08 11:00:47 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/pressure/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-01-08 11:00:47 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '%',
|
|
|
|
'device_class': 'battery',
|
|
|
|
'value_template': '{{ value_json.battery }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_battery',
|
|
|
|
'unique_id': '0x0017880104e45522_battery_zigbee2mqtt',
|
2019-01-08 11:00:47 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-01-08 11:00:47 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/battery/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-02-20 12:10:38 -07:00
|
|
|
|
|
|
|
payload = {
|
2020-01-26 11:57:15 -07:00
|
|
|
'icon': 'mdi:signal',
|
|
|
|
'unit_of_measurement': 'lqi',
|
2019-02-20 12:10:38 -07:00
|
|
|
'value_template': '{{ value_json.linkquality }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_linkquality',
|
|
|
|
'unique_id': '0x0017880104e45522_linkquality_zigbee2mqtt',
|
2019-02-20 12:10:38 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-02-20 12:10:38 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/linkquality/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-01-08 11:00:47 -07:00
|
|
|
});
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should discover devices with precision', async () => {
|
|
|
|
settings.set(['devices', '0x0017880104e45522'], {
|
2019-03-09 20:11:50 -07:00
|
|
|
humidity_precision: 0,
|
|
|
|
temperature_precision: 1,
|
|
|
|
pressure_precision: 2,
|
2019-09-09 10:48:09 -07:00
|
|
|
friendly_name: 'weather_sensor',
|
2019-09-25 03:08:39 -07:00
|
|
|
retain: false,
|
2019-09-09 10:48:09 -07:00
|
|
|
})
|
2019-01-08 11:00:47 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
|
|
|
|
|
|
|
let payload;
|
|
|
|
await flushPromises();
|
2019-01-08 11:00:47 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '°C',
|
|
|
|
'device_class': 'temperature',
|
2019-09-09 10:48:09 -07:00
|
|
|
'value_template': "{{ (value_json.temperature | float) | round(1) }}",
|
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_temperature',
|
|
|
|
'unique_id': '0x0017880104e45522_temperature_zigbee2mqtt',
|
2019-01-08 11:00:47 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-01-08 11:00:47 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/temperature/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-01-08 11:00:47 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '%',
|
|
|
|
'device_class': 'humidity',
|
|
|
|
'value_template': '{{ (value_json.humidity | float) | round(0) }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_humidity',
|
|
|
|
'unique_id': '0x0017880104e45522_humidity_zigbee2mqtt',
|
2019-01-08 11:00:47 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-01-08 11:00:47 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/humidity/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-01-08 11:00:47 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': 'hPa',
|
|
|
|
'device_class': 'pressure',
|
|
|
|
'value_template': '{{ (value_json.pressure | float) | round(2) }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_pressure',
|
|
|
|
'unique_id': '0x0017880104e45522_pressure_zigbee2mqtt',
|
2019-02-20 12:10:38 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-02-20 12:10:38 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/pressure/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-01-08 11:00:47 -07:00
|
|
|
});
|
2019-02-09 11:42:31 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should discover devices with overriden user configuration', async () => {
|
|
|
|
settings.set(['devices', '0x0017880104e45522'], {
|
2019-03-09 20:11:50 -07:00
|
|
|
homeassistant: {
|
|
|
|
expire_after: 30,
|
|
|
|
icon: 'mdi:test',
|
|
|
|
temperature: {
|
|
|
|
expire_after: 90,
|
2019-09-09 10:48:09 -07:00
|
|
|
device: {
|
|
|
|
manufacturer: 'From Xiaomi',
|
|
|
|
sw_version: 'test'
|
|
|
|
}
|
2019-02-09 11:42:31 -07:00
|
|
|
},
|
2019-09-09 10:48:09 -07:00
|
|
|
humidity: {
|
|
|
|
unique_id: null,
|
|
|
|
},
|
|
|
|
device: {
|
|
|
|
manufacturer: 'Not from Xiaomi',
|
|
|
|
model: 'custom model',
|
|
|
|
}
|
2019-03-09 20:11:50 -07:00
|
|
|
},
|
2019-09-09 10:48:09 -07:00
|
|
|
friendly_name: 'weather_sensor',
|
2019-09-25 03:08:39 -07:00
|
|
|
retain: false,
|
2019-09-09 10:48:09 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
2019-02-09 11:42:31 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
let payload;
|
|
|
|
await flushPromises();
|
2019-02-09 11:42:31 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '°C',
|
|
|
|
'device_class': 'temperature',
|
|
|
|
'value_template': '{{ value_json.temperature }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_temperature',
|
|
|
|
'unique_id': '0x0017880104e45522_temperature_zigbee2mqtt',
|
2019-02-09 11:42:31 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': 'test',
|
|
|
|
'model': 'custom model',
|
|
|
|
'manufacturer': 'From Xiaomi',
|
2019-02-09 11:42:31 -07:00
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
2019-09-09 10:48:09 -07:00
|
|
|
'expire_after': 90,
|
|
|
|
'icon': 'mdi:test',
|
2019-02-09 11:42:31 -07:00
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/temperature/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-02-09 11:42:31 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '%',
|
|
|
|
'device_class': 'humidity',
|
|
|
|
'value_template': '{{ value_json.humidity }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_humidity',
|
2019-02-09 11:42:31 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
|
|
|
'model': 'custom model',
|
|
|
|
'manufacturer': 'Not from Xiaomi',
|
2019-02-09 11:42:31 -07:00
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
'expire_after': 30,
|
|
|
|
'icon': 'mdi:test',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/humidity/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-02-09 11:42:31 -07:00
|
|
|
});
|
2019-02-23 08:02:45 -07:00
|
|
|
|
2019-10-07 12:58:35 -07:00
|
|
|
it('Shouldnt discover devices when homeassistant null is set in device options', async () => {
|
|
|
|
settings.set(['devices', '0x0017880104e45522'], {
|
|
|
|
homeassistant: null,
|
|
|
|
friendly_name: 'weather_sensor',
|
|
|
|
retain: false,
|
|
|
|
})
|
|
|
|
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
|
|
|
|
|
|
|
await flushPromises();
|
|
|
|
|
|
|
|
const topics = MQTT.publish.mock.calls.map((c) => c[0]);
|
|
|
|
expect(topics).not.toContain('homeassistant/sensor/0x0017880104e45522/humidity/config')
|
|
|
|
expect(topics).not.toContain('homeassistant/sensor/0x0017880104e45522/temperature/config')
|
|
|
|
});
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should discover devices with fan', async () => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
2019-04-26 12:57:38 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
let payload;
|
|
|
|
await flushPromises();
|
2019-04-26 12:57:38 -07:00
|
|
|
|
|
|
|
payload = {
|
2019-09-09 10:48:09 -07:00
|
|
|
"state_topic":"zigbee2mqtt/fan",
|
|
|
|
"state_value_template":"{{ value_json.fan_state }}",
|
|
|
|
"command_topic":"zigbee2mqtt/fan/set/fan_state",
|
|
|
|
"speed_state_topic":"zigbee2mqtt/fan",
|
|
|
|
"speed_command_topic":"zigbee2mqtt/fan/set/fan_mode",
|
|
|
|
"speed_value_template":"{{ value_json.fan_mode }}",
|
|
|
|
"speeds":[
|
|
|
|
"off",
|
|
|
|
"low",
|
|
|
|
"medium",
|
|
|
|
"high",
|
|
|
|
"on",
|
|
|
|
"auto",
|
|
|
|
"smart"
|
|
|
|
],
|
|
|
|
"json_attributes_topic":"zigbee2mqtt/fan",
|
|
|
|
"name":"fan_fan",
|
|
|
|
"unique_id":"0x0017880104e45548_fan_zigbee2mqtt",
|
|
|
|
"device":{
|
|
|
|
"identifiers":[
|
|
|
|
"zigbee2mqtt_0x0017880104e45548"
|
|
|
|
],
|
|
|
|
"name":"fan",
|
|
|
|
"sw_version":this.version,
|
|
|
|
"model":"Universal wink enabled white ceiling fan premier remote control (99432)",
|
|
|
|
"manufacturer":"Hampton Bay"
|
2019-04-26 12:57:38 -07:00
|
|
|
},
|
2019-09-09 10:48:09 -07:00
|
|
|
"availability_topic":"zigbee2mqtt/bridge/state"
|
|
|
|
};
|
|
|
|
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/fan/0x0017880104e45548/fan/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-04-26 12:57:38 -07:00
|
|
|
});
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should discover devices with cover_position', async () => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
2019-02-23 08:02:45 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
let payload;
|
|
|
|
await flushPromises();
|
2019-02-23 08:02:45 -07:00
|
|
|
|
|
|
|
payload = {
|
2019-09-09 10:48:09 -07:00
|
|
|
command_topic: 'zigbee2mqtt/smart_vent/set',
|
|
|
|
position_topic: 'zigbee2mqtt/smart_vent',
|
|
|
|
set_position_topic: 'zigbee2mqtt/smart_vent/set',
|
2019-02-23 08:02:45 -07:00
|
|
|
set_position_template: '{ "position": {{ position }} }',
|
|
|
|
value_template: '{{ value_json.position }}',
|
2019-11-20 09:35:49 -07:00
|
|
|
json_attributes_topic: 'zigbee2mqtt/smart_vent',
|
2019-09-09 10:48:09 -07:00
|
|
|
name: 'smart_vent_cover',
|
|
|
|
unique_id: '0x0017880104e45551_cover_zigbee2mqtt',
|
|
|
|
device:
|
|
|
|
{
|
|
|
|
identifiers: [ 'zigbee2mqtt_0x0017880104e45551' ],
|
|
|
|
name: 'smart_vent',
|
|
|
|
sw_version: this.version,
|
|
|
|
model: 'Smart vent (SV01)',
|
|
|
|
manufacturer: 'Keen Home'
|
2019-02-23 08:02:45 -07:00
|
|
|
},
|
2019-09-09 10:48:09 -07:00
|
|
|
availability_topic: 'zigbee2mqtt/bridge/state'
|
2019-02-23 08:02:45 -07:00
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/cover/0x0017880104e45551/cover/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-02-23 08:02:45 -07:00
|
|
|
});
|
2019-03-10 13:48:40 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should discover devices with custom homeassistant_discovery_topic', async () => {
|
|
|
|
settings.set(['advanced', 'homeassistant_discovery_topic'], 'my_custom_discovery_topic')
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
2019-03-10 13:48:40 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
let payload;
|
|
|
|
await flushPromises();
|
2019-03-10 13:48:40 -07:00
|
|
|
|
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '°C',
|
|
|
|
'device_class': 'temperature',
|
|
|
|
'value_template': '{{ value_json.temperature }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_temperature',
|
|
|
|
'unique_id': '0x0017880104e45522_temperature_zigbee2mqtt',
|
2019-03-10 13:48:40 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-03-10 13:48:40 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'my_custom_discovery_topic/sensor/0x0017880104e45522/temperature/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-03-10 13:48:40 -07:00
|
|
|
});
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should throw error when starting with attributes output', async () => {
|
|
|
|
settings.set(['experimental', 'output'], 'attribute')
|
|
|
|
expect(() => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
}).toThrowError('Home Assitant integration is not possible with attribute output!');
|
|
|
|
});
|
2019-03-10 13:48:40 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should warn when starting with cache_state false', async () => {
|
|
|
|
settings.set(['advanced', 'cache_state'], false);
|
|
|
|
logger.warn.mockClear();
|
|
|
|
controller = new Controller(false);
|
|
|
|
expect(logger.warn).toHaveBeenCalledWith("In order for HomeAssistant integration to work properly set `cache_state: true");
|
|
|
|
});
|
2019-03-10 13:48:40 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Shouldt discover when already discovered', async () => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
const device = zigbeeHerdsman.devices.WSDCGQ11LM;
|
|
|
|
const data = {measuredValue: -85}
|
|
|
|
const payload = {data, cluster: 'msTemperatureMeasurement', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10};
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
await zigbeeHerdsman.events.message(payload);
|
|
|
|
await flushPromises();
|
|
|
|
// 1 publish is the publish from deviceReceive
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Should discover when not discovered yet', async () => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
controller.extensions.find((e) => e.constructor.name === 'HomeAssistant').discovered = {};
|
|
|
|
const device = zigbeeHerdsman.devices.WSDCGQ11LM;
|
|
|
|
const data = {measuredValue: -85}
|
|
|
|
const payload = {data, cluster: 'msTemperatureMeasurement', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10};
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
await zigbeeHerdsman.events.message(payload);
|
|
|
|
await flushPromises();
|
|
|
|
const payloadHA = {
|
2019-03-10 13:48:40 -07:00
|
|
|
'unit_of_measurement': '°C',
|
|
|
|
'device_class': 'temperature',
|
|
|
|
'value_template': '{{ value_json.temperature }}',
|
2019-09-09 10:48:09 -07:00
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_temperature',
|
|
|
|
'unique_id': '0x0017880104e45522_temperature_zigbee2mqtt',
|
2019-03-10 13:48:40 -07:00
|
|
|
'device': {
|
2019-09-09 10:48:09 -07:00
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
2019-03-10 13:48:40 -07:00
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/bridge/state',
|
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/temperature/config',
|
|
|
|
JSON.stringify(payloadHA),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-03-10 13:48:40 -07:00
|
|
|
});
|
2019-03-15 14:41:39 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Shouldnt discover when message has no device yet', async () => {
|
|
|
|
controller = new Controller();
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
controller.extensions.find((e) => e.constructor.name === 'HomeAssistant').discovered = {};
|
|
|
|
const device = zigbeeHerdsman.devices.bulb;
|
|
|
|
const payload = {ieeeAddr: device.ieeeAddr};
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
await zigbeeHerdsman.events.deviceLeave(payload);
|
|
|
|
await flushPromises();
|
|
|
|
// 1 publish is from device_removed
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
2019-03-15 14:41:39 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should send all status when home assistant comes online', async () => {
|
|
|
|
jest.useFakeTimers();
|
|
|
|
data.writeDefaultState();
|
|
|
|
controller = new Controller();
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
await MQTT.events.message('hass/status', 'online');
|
|
|
|
await flushPromises();
|
|
|
|
jest.runOnlyPendingTimers();
|
|
|
|
await flushPromises();
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'zigbee2mqtt/bulb',
|
|
|
|
'{"state":"ON","brightness":50,"color_temp":370,"linkquality":99}',
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function)
|
|
|
|
);
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'zigbee2mqtt/remote',
|
|
|
|
'{"brightness":255}',
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function)
|
|
|
|
);
|
|
|
|
});
|
2019-03-15 14:41:39 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Shouldnt send all status when home assistant comes offline', async () => {
|
|
|
|
jest.useFakeTimers();
|
|
|
|
data.writeDefaultState();
|
|
|
|
controller = new Controller();
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
await MQTT.events.message('hass/status', 'offline');
|
|
|
|
await flushPromises();
|
|
|
|
jest.runOnlyPendingTimers();
|
|
|
|
await flushPromises();
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledTimes(0);
|
|
|
|
});
|
2019-03-15 14:41:39 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Shouldnt send all status when home assistant comes online with different topic', async () => {
|
|
|
|
jest.useFakeTimers();
|
|
|
|
data.writeDefaultState();
|
|
|
|
controller = new Controller();
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
await MQTT.events.message('hass/status_different', 'offline');
|
|
|
|
await flushPromises();
|
|
|
|
jest.runOnlyPendingTimers();
|
|
|
|
await flushPromises();
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledTimes(0);
|
2019-06-24 11:52:47 -07:00
|
|
|
});
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
it('Should discover devices with availability', async () => {
|
|
|
|
settings.set(['advanced', 'availability_timeout'], 1)
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
2019-06-24 11:52:47 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
let payload;
|
|
|
|
await flushPromises();
|
2019-06-24 11:52:47 -07:00
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
payload = {
|
|
|
|
'unit_of_measurement': '°C',
|
|
|
|
'device_class': 'temperature',
|
|
|
|
'value_template': '{{ value_json.temperature }}',
|
|
|
|
'state_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'json_attributes_topic': 'zigbee2mqtt/weather_sensor',
|
|
|
|
'name': 'weather_sensor_temperature',
|
|
|
|
'unique_id': '0x0017880104e45522_temperature_zigbee2mqtt',
|
|
|
|
'device': {
|
|
|
|
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
|
|
|
'name': 'weather_sensor',
|
|
|
|
'sw_version': this.version,
|
|
|
|
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
|
|
|
'manufacturer': 'Xiaomi',
|
|
|
|
},
|
|
|
|
'availability_topic': 'zigbee2mqtt/weather_sensor/availability',
|
2019-06-24 11:52:47 -07:00
|
|
|
};
|
|
|
|
|
2019-09-09 10:48:09 -07:00
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/temperature/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
2019-03-15 14:41:39 -07:00
|
|
|
});
|
2020-01-09 13:47:19 -07:00
|
|
|
|
|
|
|
it('Should clear discovery when device is removed', async () => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
MQTT.events.message('zigbee2mqtt/bridge/config/remove', 'weather_sensor');
|
|
|
|
await flushPromises();
|
|
|
|
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/temperature/config',
|
|
|
|
null,
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/humidity/config',
|
|
|
|
null,
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/pressure/config',
|
|
|
|
null,
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/battery/config',
|
|
|
|
null,
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/sensor/0x0017880104e45522/linkquality/config',
|
|
|
|
null,
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Should not clear discovery when unsupported device is removed', async () => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
MQTT.publish.mockClear();
|
|
|
|
MQTT.events.message('zigbee2mqtt/bridge/config/remove', 'unsupported2');
|
|
|
|
await flushPromises();
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
2020-02-16 08:00:15 -07:00
|
|
|
|
|
|
|
it('Should discover update_available sensor when device supports it', async () => {
|
|
|
|
controller = new Controller(false);
|
|
|
|
await controller.start();
|
|
|
|
await flushPromises();
|
|
|
|
const payload = {
|
|
|
|
"payload_on":true,
|
|
|
|
"payload_off":false,
|
|
|
|
"value_template":"{{ value_json.update_available}}",
|
|
|
|
"state_topic":"zigbee2mqtt/bulb",
|
|
|
|
"json_attributes_topic":"zigbee2mqtt/bulb",
|
|
|
|
"name":"bulb_update_available",
|
|
|
|
"unique_id":"0x000b57fffec6a5b2_update_available_zigbee2mqtt",
|
|
|
|
"device":{
|
|
|
|
"identifiers":[
|
|
|
|
"zigbee2mqtt_0x000b57fffec6a5b2"
|
|
|
|
],
|
|
|
|
"name":"bulb",
|
|
|
|
'sw_version': this.version,
|
|
|
|
"model":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white (LED1545G12)",
|
|
|
|
"manufacturer":"IKEA"
|
|
|
|
},
|
|
|
|
"availability_topic":"zigbee2mqtt/bridge/state"
|
|
|
|
};
|
|
|
|
|
|
|
|
expect(MQTT.publish).toHaveBeenCalledWith(
|
|
|
|
'homeassistant/binary_sensor/0x000b57fffec6a5b2/update_available/config',
|
|
|
|
JSON.stringify(payload),
|
|
|
|
{ retain: true, qos: 0 },
|
|
|
|
expect.any(Function),
|
|
|
|
);
|
|
|
|
});
|
2018-11-16 12:23:11 -07:00
|
|
|
});
|