2019-09-09 10:48:09 -07:00
const data = require ( './stub/data' ) ;
const logger = require ( './stub/logger' ) ;
const zigbeeHerdsman = require ( './stub/zigbeeHerdsman' ) ;
const MQTT = require ( './stub/mqtt' ) ;
const path = require ( 'path' ) ;
const mockExit = jest . spyOn ( process , 'exit' ) . mockImplementation ( ( ) => { } ) ;
2018-11-28 11:34:37 -07:00
const settings = require ( '../lib/util/settings' ) ;
2019-09-09 10:48:09 -07:00
const Controller = require ( '../lib/controller' ) ;
const flushPromises = ( ) => new Promise ( setImmediate ) ;
const tmp = require ( 'tmp' ) ;
const mocksClear = [
zigbeeHerdsman . permitJoin , mockExit , MQTT . end , zigbeeHerdsman . stop , logger . debug ,
MQTT . publish , MQTT . connect , zigbeeHerdsman . devices . bulb _color . removeFromNetwork ,
2019-09-25 03:08:39 -07:00
zigbeeHerdsman . devices . bulb . removeFromNetwork , logger . error ,
2019-09-09 10:48:09 -07:00
] ;
const fs = require ( 'fs' ) ;
2018-11-28 11:34:37 -07:00
describe ( 'Controller' , ( ) => {
let controller ;
beforeEach ( ( ) => {
2019-09-25 16:14:58 -07:00
zigbeeHerdsman . returnDevices . splice ( 0 ) ;
2018-11-28 11:34:37 -07:00
controller = new Controller ( ) ;
2019-09-09 10:48:09 -07:00
mocksClear . forEach ( ( m ) => m . mockClear ( ) ) ;
data . writeDefaultConfiguration ( ) ;
settings . _reRead ( ) ;
data . writeDefaultState ( ) ;
} ) ;
it ( 'Start controller' , async ( ) => {
await controller . start ( ) ;
2019-11-06 11:43:12 -07:00
expect ( zigbeeHerdsman . constructor ) . toHaveBeenCalledWith ( { "network" : { "panID" : 6754 , "extendedPanID" : [ 221 , 221 , 221 , 221 , 221 , 221 , 221 , 221 ] , "channelList" : [ 11 ] , "networkKey" : [ 1 , 3 , 5 , 7 , 9 , 11 , 13 , 15 , 0 , 2 , 4 , 6 , 8 , 10 , 12 , 13 ] } , "databasePath" : path . join ( data . mockDir , "database.db" ) , "databaseBackupPath" : path . join ( data . mockDir , "database.db.backup" ) , "backupPath" : path . join ( data . mockDir , "coordinator_backup.json" ) , "acceptJoiningDeviceHandler" : expect . any ( Function ) , "serialPort" : { "baudRate" : 115200 , "rtscts" : true , "path" : "/dev/dummy" } } ) ;
2019-09-09 10:48:09 -07:00
expect ( zigbeeHerdsman . start ) . toHaveBeenCalledTimes ( 1 ) ;
2019-09-30 12:16:00 -07:00
expect ( zigbeeHerdsman . setLED ) . toHaveBeenCalledTimes ( 0 ) ;
2019-11-27 14:02:49 -07:00
expect ( zigbeeHerdsman . setTransmitPower ) . toHaveBeenCalledTimes ( 0 ) ;
2019-09-09 10:48:09 -07:00
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledWith ( true ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( ` Currently ${ Object . values ( zigbeeHerdsman . devices ) . length - 1 } devices are joined: ` )
expect ( logger . info ) . toHaveBeenCalledWith ( 'bulb (0x000b57fffec6a5b2): LED1545G12 - IKEA TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white (Router)' ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( 'remote (0x0017880104e45517): 324131092621 - Philips Hue dimmer switch (EndDevice)' ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( '0x0017880104e45518 (0x0017880104e45518): Not supported (EndDevice)' ) ;
expect ( MQTT . connect ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( MQTT . connect ) . toHaveBeenCalledWith ( "mqtt://localhost" , { "will" : { "payload" : "offline" , "retain" : true , "topic" : "zigbee2mqtt/bridge/state" } } ) ;
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 ) ) ;
} ) ;
it ( 'Start controller with specific MQTT settings' , async ( ) => {
const ca = tmp . fileSync ( ) . name ;
fs . writeFileSync ( ca , "ca" ) ;
const key = tmp . fileSync ( ) . name ;
fs . writeFileSync ( key , "key" ) ;
const cert = tmp . fileSync ( ) . name ;
fs . writeFileSync ( cert , "cert" ) ;
const configuration = {
base _topic : "zigbee2mqtt" ,
server : "mqtt://localhost" ,
2020-01-17 13:38:46 -07:00
keepalive : 30 ,
2019-09-09 10:48:09 -07:00
ca , cert , key ,
password : 'pass' ,
user : 'user1' ,
client _id : 'my_client_id' ,
reject _unauthorized : false ,
}
settings . set ( [ 'mqtt' ] , configuration )
await controller . start ( ) ;
await flushPromises ( ) ;
expect ( MQTT . connect ) . toHaveBeenCalledTimes ( 1 ) ;
const expected = {
"will" : { "payload" : "offline" , "retain" : true , "topic" : "zigbee2mqtt/bridge/state" } ,
2020-01-17 13:38:46 -07:00
keepalive : 30 ,
2019-09-09 10:48:09 -07:00
ca : Buffer . from ( [ 99 , 97 ] ) ,
key : Buffer . from ( [ 107 , 101 , 121 ] ) ,
cert : Buffer . from ( [ 99 , 101 , 114 , 116 ] ) ,
password : 'pass' ,
username : 'user1' ,
clientId : 'my_client_id' ,
rejectUnauthorized : false ,
}
expect ( MQTT . connect ) . toHaveBeenCalledWith ( "mqtt://localhost" , expected ) ;
} ) ;
2019-09-25 04:15:30 -07:00
it ( 'Start controller should publish cached states' , async ( ) => {
data . writeDefaultState ( ) ;
await controller . start ( ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb" , ` {"state":"ON","brightness":50,"color_temp":370,"linkquality":99} ` , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/remote" , ` {"brightness":255} ` , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
} ) ;
it ( 'Start controller should not publish cached states when cache_state is false' , async ( ) => {
settings . set ( [ 'advanced' , 'cache_state' ] , false ) ;
data . writeDefaultState ( ) ;
await controller . start ( ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . not . toHaveBeenCalledWith ( "zigbee2mqtt/bulb" , ` {"state":"ON","brightness":50,"color_temp":370,"linkquality":99} ` , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . not . toHaveBeenCalledWith ( "zigbee2mqtt/remote" , ` {"brightness":255} ` , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
} ) ;
2019-09-09 10:48:09 -07:00
it ( 'Log when MQTT client is unavailable' , async ( ) => {
jest . useFakeTimers ( ) ;
await controller . start ( ) ;
await flushPromises ( ) ;
logger . error . mockClear ( ) ;
controller . mqtt . client . reconnecting = true ;
jest . advanceTimersByTime ( 11 * 1000 ) ;
await flushPromises ( ) ;
expect ( logger . error ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( logger . error ) . toHaveBeenCalledWith ( "Not connected to MQTT server!" ) ;
controller . mqtt . client . reconnecting = false ;
} ) ;
it ( 'Dont publish to mqtt when client is unavailable' , async ( ) => {
await controller . start ( ) ;
await flushPromises ( ) ;
logger . error . mockClear ( ) ;
controller . mqtt . client . reconnecting = true ;
await controller . publishEntityState ( 'bulb' , { state : 'ON' , brightness : 50 , color _temp : 370 , color : { r : 100 , g : 50 , b : 10 } , dummy : { 1 : 'yes' , 2 : 'no' } } ) ;
await flushPromises ( ) ;
expect ( logger . error ) . toHaveBeenCalledTimes ( 2 ) ;
expect ( logger . error ) . toHaveBeenCalledWith ( "Not connected to MQTT server!" ) ;
expect ( logger . error ) . toHaveBeenCalledWith ( "Cannot send message: topic: 'zigbee2mqtt/bulb', payload: '{\"state\":\"ON\",\"brightness\":50,\"color_temp\":370,\"linkquality\":99,\"color\":{\"r\":100,\"g\":50,\"b\":10},\"dummy\":{\"1\":\"yes\",\"2\":\"no\"}}" ) ;
controller . mqtt . client . reconnecting = false ;
} ) ;
it ( 'Load empty state when state file does not exist' , async ( ) => {
data . removeState ( ) ;
await controller . start ( ) ;
await flushPromises ( ) ;
expect ( controller . state . state ) . toStrictEqual ( { } ) ;
} ) ;
it ( 'Should remove non whitelisted devices on startup' , async ( ) => {
settings . set ( [ 'whitelist' ] , [ zigbeeHerdsman . devices . bulb _color . ieeeAddr ] ) ;
await controller . start ( ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . devices . bulb _color . removeFromNetwork ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( zigbeeHerdsman . devices . bulb . removeFromNetwork ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
it ( 'Should remove banned devices on startup' , async ( ) => {
settings . set ( [ 'ban' ] , [ zigbeeHerdsman . devices . bulb _color . ieeeAddr ] ) ;
await controller . start ( ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . devices . bulb _color . removeFromNetwork ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . devices . bulb . removeFromNetwork ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
it ( 'Start controller fails' , async ( ) => {
zigbeeHerdsman . start . mockImplementationOnce ( ( ) => { throw new Error ( 'failed' ) } ) ;
await controller . start ( ) ;
expect ( mockExit ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
it ( 'Start controller with permit join true' , async ( ) => {
settings . set ( [ 'permit_join' ] , false ) ;
await controller . start ( ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledWith ( false ) ;
} ) ;
2019-09-25 03:08:39 -07:00
it ( 'Refuse to start when configuration.yaml is invalid' , async ( ) => {
settings . set ( [ 'permit_join' ] , 'invalid' ) ;
await controller . start ( ) ;
expect ( logger . error ) . toHaveBeenCalledWith ( 'Refusing to start, configuration.yaml is not valid, found the following errors:' ) ;
expect ( logger . error ) . toHaveBeenCalledWith ( '\t - permit_join should be boolean' ) ;
expect ( mockExit ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mockExit ) . toHaveBeenCalledWith ( 1 ) ;
} ) ;
2019-09-30 12:16:00 -07:00
it ( 'Start controller with disable_led' , async ( ) => {
2019-09-09 10:48:09 -07:00
settings . set ( [ 'serial' , 'disable_led' ] , true ) ;
await controller . start ( ) ;
2019-09-30 12:16:00 -07:00
expect ( zigbeeHerdsman . setLED ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . setLED ) . toHaveBeenCalledWith ( false ) ;
2019-09-09 10:48:09 -07:00
} ) ;
2019-11-27 14:02:49 -07:00
it ( 'Start controller with transmit power' , async ( ) => {
settings . set ( [ 'experimental' , 'transmit_power' ] , 14 ) ;
await controller . start ( ) ;
expect ( zigbeeHerdsman . setTransmitPower ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . setTransmitPower ) . toHaveBeenCalledWith ( 14 ) ;
} ) ;
2019-09-09 10:48:09 -07:00
it ( 'Start controller and stop' , async ( ) => {
await controller . start ( ) ;
await controller . stop ( ) ;
expect ( MQTT . end ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . stop ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mockExit ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mockExit ) . toHaveBeenCalledWith ( 0 ) ;
} ) ;
it ( 'Start controller and stop' , async ( ) => {
zigbeeHerdsman . stop . mockImplementationOnce ( ( ) => { throw new Error ( 'failed' ) } )
await controller . start ( ) ;
await controller . stop ( ) ;
expect ( MQTT . end ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . stop ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mockExit ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mockExit ) . toHaveBeenCalledWith ( 1 ) ;
} ) ;
it ( 'Start controller adapter disconnects' , async ( ) => {
zigbeeHerdsman . stop . mockImplementationOnce ( ( ) => { throw new Error ( 'failed' ) } )
await controller . start ( ) ;
await zigbeeHerdsman . events . adapterDisconnected ( ) ;
await flushPromises ( ) ;
expect ( MQTT . end ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . stop ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mockExit ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mockExit ) . toHaveBeenCalledWith ( 1 ) ;
} ) ;
it ( 'Handle mqtt message' , async ( ) => {
await controller . start ( ) ;
logger . debug . mockClear ( ) ;
await MQTT . events . message ( 'dummytopic' , 'dummymessage' ) ;
expect ( logger . debug ) . toHaveBeenCalledWith ( "Received MQTT message on 'dummytopic' with data 'dummymessage'" )
} ) ;
it ( 'On zigbee event message' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const payload = { device , endpoint : device . getEndpoint ( 1 ) , type : 'attributeReport' , linkquality : 10 , cluster : 'genBasic' , data : { modelId : device . modelID } } ;
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
2019-10-01 11:58:08 -07:00
expect ( logger . debug ) . toHaveBeenCalledWith ( ` Received Zigbee message from 'bulb', type 'attributeReport', cluster 'genBasic', data '{"modelId":"TRADFRI bulb E27 WS opal 980lm"}' from endpoint 1 ` ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'On zigbee event message with group ID' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const payload = { device , endpoint : device . getEndpoint ( 1 ) , type : 'attributeReport' , linkquality : 10 , groupID : 0 , cluster : 'genBasic' , data : { modelId : device . modelID } } ;
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
2019-10-01 11:58:08 -07:00
expect ( logger . debug ) . toHaveBeenCalledWith ( ` Received Zigbee message from 'bulb', type 'attributeReport', cluster 'genBasic', data '{"modelId":"TRADFRI bulb E27 WS opal 980lm"}' from endpoint 1 with groupID 0 ` ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'On zigbee event message from unkown device should create it' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . notInSettings ;
expect ( settings . getDevice ( device . ieeeAddr ) ) . toBeNull ( ) ;
const payload = { device , endpoint : device . getEndpoint ( 1 ) , type : 'attributeReport' , linkquality : 10 , groupID : 0 , cluster : 'genBasic' , data : { modelId : device . modelID } } ;
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
2019-11-06 12:30:33 -07:00
expect ( settings . getDevice ( device . ieeeAddr ) ) . toStrictEqual ( { "ID" : "0x0017880104e45519" , "friendlyName" : "0x0017880104e45519" , "friendly_name" : "0x0017880104e45519" } ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'On zigbee deviceJoined' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const payload = { device } ;
await zigbeeHerdsman . events . deviceJoined ( payload ) ;
await flushPromises ( ) ;
2019-09-15 00:13:02 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bridge/log" , '{"type":"device_connected","message":{"friendly_name":"bulb"}}' , { "retain" : false , qos : 0 } , expect . any ( Function ) ) ;
2019-09-09 10:48:09 -07:00
} ) ;
2019-10-17 13:01:39 -07:00
it ( 'acceptJoiningDeviceHandler reject banned device' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
settings . set ( [ 'ban' ] , [ device . ieeeAddr ] ) ;
const handler = zigbeeHerdsman . constructor . mock . calls [ 0 ] [ 0 ] . acceptJoiningDeviceHandler ;
expect ( await handler ( device . ieeeAddr ) ) . toBe ( false ) ;
} ) ;
it ( 'acceptJoiningDeviceHandler accept not banned device' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
settings . set ( [ 'ban' ] , [ '123' ] ) ;
const handler = zigbeeHerdsman . constructor . mock . calls [ 0 ] [ 0 ] . acceptJoiningDeviceHandler ;
expect ( await handler ( device . ieeeAddr ) ) . toBe ( true ) ;
} ) ;
it ( 'acceptJoiningDeviceHandler accept whitelisted device' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
settings . set ( [ 'whitelist' ] , [ device . ieeeAddr ] ) ;
const handler = zigbeeHerdsman . constructor . mock . calls [ 0 ] [ 0 ] . acceptJoiningDeviceHandler ;
expect ( await handler ( device . ieeeAddr ) ) . toBe ( true ) ;
} ) ;
it ( 'acceptJoiningDeviceHandler reject non-whitelisted device' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
settings . set ( [ 'whitelist' ] , [ '123' ] ) ;
const handler = zigbeeHerdsman . constructor . mock . calls [ 0 ] [ 0 ] . acceptJoiningDeviceHandler ;
expect ( await handler ( device . ieeeAddr ) ) . toBe ( false ) ;
} ) ;
it ( 'acceptJoiningDeviceHandler should prefer whitelist above ban' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
settings . set ( [ 'whitelist' ] , [ device . ieeeAddr ] ) ;
settings . set ( [ 'ban' ] , [ device . ieeeAddr ] ) ;
const handler = zigbeeHerdsman . constructor . mock . calls [ 0 ] [ 0 ] . acceptJoiningDeviceHandler ;
expect ( await handler ( device . ieeeAddr ) ) . toBe ( true ) ;
} ) ;
2019-10-26 09:05:40 -07:00
it ( 'acceptJoiningDeviceHandler accept when no ban and whitelist' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const handler = zigbeeHerdsman . constructor . mock . calls [ 0 ] [ 0 ] . acceptJoiningDeviceHandler ;
expect ( await handler ( device . ieeeAddr ) ) . toBe ( true ) ;
} ) ;
2019-09-23 13:24:03 -07:00
it ( 'Shouldnt crash when two device join events are received' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const payload = { device } ;
zigbeeHerdsman . events . deviceJoined ( payload ) ;
zigbeeHerdsman . events . deviceJoined ( payload ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bridge/log" , '{"type":"device_connected","message":{"friendly_name":"bulb"}}' , { "retain" : false , qos : 0 } , expect . any ( Function ) ) ;
} ) ;
2019-09-09 10:48:09 -07:00
it ( 'On zigbee deviceInterview started' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const payload = { device , status : 'started' } ;
await zigbeeHerdsman . events . deviceInterview ( payload ) ;
await flushPromises ( ) ;
2019-09-15 00:13:02 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/log' , '{"type":"pairing","message":"interview_started","meta":{"friendly_name":"bulb"}}' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'On zigbee deviceInterview failed' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const payload = { device , status : 'failed' } ;
await zigbeeHerdsman . events . deviceInterview ( payload ) ;
await flushPromises ( ) ;
2019-09-15 00:13:02 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/log' , '{"type":"pairing","message":"interview_failed","meta":{"friendly_name":"bulb"}}' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'On zigbee deviceInterview successful supported' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const payload = { device , status : 'successful' } ;
await zigbeeHerdsman . events . deviceInterview ( payload ) ;
await flushPromises ( ) ;
2019-09-15 00:13:02 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/log' , '{"type":"pairing","message":"interview_successful","meta":{"friendly_name":"bulb","model":"LED1545G12","vendor":"IKEA","description":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white","supported":true}}' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'On zigbee deviceInterview successful not supported' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . unsupported ;
const payload = { device , status : 'successful' } ;
await zigbeeHerdsman . events . deviceInterview ( payload ) ;
await flushPromises ( ) ;
2019-09-15 00:13:02 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/log' , '{"type":"pairing","message":"interview_successful","meta":{"friendly_name":"0x0017880104e45518","supported":false}}' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'On zigbee event device announce' , async ( ) => {
await controller . start ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
const payload = { device } ;
await zigbeeHerdsman . events . deviceAnnounce ( payload ) ;
await flushPromises ( ) ;
expect ( logger . debug ) . toHaveBeenCalledWith ( ` Device 'bulb' announced itself ` ) ;
} ) ;
2019-09-25 16:14:58 -07:00
it ( 'On zigbee event device leave (removed from database and settings)' , async ( ) => {
2019-09-09 10:48:09 -07:00
await controller . start ( ) ;
2019-09-25 16:14:58 -07:00
zigbeeHerdsman . returnDevices . push ( '0x00124b00120144ae' ) ;
settings . set ( [ 'devices' ] , { } )
MQTT . publish . mockClear ( ) ;
2019-09-09 10:48:09 -07:00
const device = zigbeeHerdsman . devices . bulb ;
const payload = { ieeeAddr : device . ieeeAddr } ;
await zigbeeHerdsman . events . deviceLeave ( payload ) ;
await flushPromises ( ) ;
2019-09-25 16:14:58 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/log' , '{"type":"device_removed","message":"left_network","meta":{"friendly_name":"0x000b57fffec6a5b2"}}' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
} ) ;
it ( 'On zigbee event device leave (removed from database and NOT settings)' , async ( ) => {
await controller . start ( ) ;
zigbeeHerdsman . returnDevices . push ( '0x00124b00120144ae' ) ;
const device = zigbeeHerdsman . devices . bulb ;
MQTT . publish . mockClear ( ) ;
const payload = { ieeeAddr : device . ieeeAddr } ;
await zigbeeHerdsman . events . deviceLeave ( payload ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/log' , '{"type":"device_removed","message":"left_network","meta":{"friendly_name":"0x000b57fffec6a5b2"}}' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'Publish entity state attribute output' , async ( ) => {
await controller . start ( ) ;
settings . set ( [ 'experimental' , 'output' ] , 'attribute' ) ;
MQTT . publish . mockClear ( ) ;
await controller . publishEntityState ( 'bulb' , { state : 'ON' , brightness : 50 , color _temp : 370 , color : { r : 100 , g : 50 , b : 10 } , dummy : { 1 : 'yes' , 2 : 'no' } } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/state" , "ON" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/brightness" , "50" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/color_temp" , "370" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/color" , '100,50,10' , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/dummy-1" , 'yes' , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/dummy-2" , 'no' , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
} ) ;
2020-01-12 07:07:06 -07:00
it ( 'Publish entity state attribute_json output' , async ( ) => {
await controller . start ( ) ;
settings . set ( [ 'experimental' , 'output' ] , 'attribute_and_json' ) ;
MQTT . publish . mockClear ( ) ;
await controller . publishEntityState ( 'bulb' , { state : 'ON' , brightness : 200 , color _temp : 370 , linkquality : 99 } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 5 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/state" , "ON" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/brightness" , "200" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/color_temp" , "370" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb/linkquality" , "99" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb" , '{"state":"ON","brightness":200,"color_temp":370,"linkquality":99}' , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
} ) ;
2019-09-23 14:59:01 -07:00
it ( 'Publish entity state with device information' , async ( ) => {
2019-09-09 10:48:09 -07:00
await controller . start ( ) ;
settings . set ( [ 'mqtt' , 'include_device_information' ] , true ) ;
MQTT . publish . mockClear ( ) ;
await controller . publishEntityState ( 'bulb' , { state : 'ON' } ) ;
await flushPromises ( ) ;
2019-12-11 12:15:42 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bulb' , '{"state":"ON","brightness":50,"color_temp":370,"linkquality":99,"device":{"friendlyName":"bulb","model":"LED1545G12","ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369,"type":"Router","manufacturerID":4476,"powerSource":"Mains (single phase)"}}' , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
// Unsupported device should have model "unknown"
await controller . publishEntityState ( 'unsupported2' , { state : 'ON' } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/unsupported2' , '{"state":"ON","device":{"friendlyName":"unsupported2","model":"unknown","ieeeAddr":"0x0017880104e45529","networkAddress":6536,"type":"EndDevice","manufacturerID":0,"powerSource":"Battery"}}' , { "qos" : 0 , "retain" : false } , expect . any ( Function ) ) ;
2019-09-09 10:48:09 -07:00
} ) ;
it ( 'Publish entity state no empty messages' , async ( ) => {
data . writeEmptyState ( ) ;
await controller . start ( ) ;
MQTT . publish . mockClear ( ) ;
await controller . publishEntityState ( 'bulb' , { } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
it ( 'Publish should not cache when set' , async ( ) => {
settings . set ( [ 'advanced' , 'cache_state' ] , false ) ;
data . writeEmptyState ( ) ;
await controller . start ( ) ;
MQTT . publish . mockClear ( ) ;
await controller . publishEntityState ( 'bulb' , { state : 'ON' } ) ;
await controller . publishEntityState ( 'bulb' , { brightness : 200 } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 2 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb" , "{\"state\":\"ON\"}" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( "zigbee2mqtt/bulb" , "{\"brightness\":200}" , { "qos" : 0 , "retain" : true } , expect . any ( Function ) ) ;
} ) ;
it ( 'Publish should not do anything for unknown entity' , async ( ) => {
await controller . start ( ) ;
MQTT . publish . mockClear ( ) ;
await controller . publishEntityState ( 'bulb-unknown' , { brightness : 200 } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 0 ) ;
2018-11-28 11:34:37 -07:00
} ) ;
2019-10-03 11:06:31 -07:00
it ( 'Should start when state is corrupted' , async ( ) => {
fs . writeFileSync ( path . join ( data . mockDir , 'state.json' ) , 'corrupted' ) ;
await controller . start ( ) ;
await flushPromises ( ) ;
expect ( controller . state . state ) . toStrictEqual ( { } ) ;
} ) ;
2018-11-28 11:34:37 -07:00
} ) ;