Skip to content

Commit

Permalink
Update NbAccessory.js
Browse files Browse the repository at this point in the history
Change startup logic:
- Need device info reported by bridge to create new _Battery_ service, see #116.
- Guard handling each device, so error for one device won't impact the next.
  • Loading branch information
ebaauw committed Jul 22, 2023
1 parent 1a7c440 commit 4c513b5
Showing 1 changed file with 110 additions and 90 deletions.
200 changes: 110 additions & 90 deletions lib/NbAccessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@ class NbAccessory extends homebridgeLib.AccessoryDelegate {
category: params.category,
manufacturer: 'Nuki Home Solutions GmbH',
model: params.model,
firmware: params.firmware
firmware: params.device.firmwareVersion
})
this.inheritLogLevel(bridge)
this.id = params.id
this.bridge = bridge
this.client = this.bridge.client
this.context.bridgeId = this.bridge.id
this.context.firmware = params.firmware
this.context.deviceType = params.deviceType
this.log('Nuki %s v%s %s', params.model, params.firmware, params.id)
this.deviceType = params.device
this.log('Nuki %s v%s %s', params.model, params.device.firmwareVersion, params.id)
this.on('identify', this.identify)
setImmediate(() => { this.emit('initialised') })
}
Expand All @@ -39,15 +38,13 @@ class NbAccessory extends homebridgeLib.AccessoryDelegate {

class Bridge extends homebridgeLib.AccessoryDelegate {
constructor (platform, context) {
const params = {
super(platform, {
id: context.id,
name: context.name,
category: platform.Accessory.Categories.RANGE_EXTENDER,
manufacturer: 'Nuki Home Solutions GmbH',
model: 'Bridge',
firmware: context.firmware
}
super(platform, params)
})
this.id = context.id
this.context.host = context.host
this.context.token = context.token
Expand Down Expand Up @@ -245,72 +242,58 @@ class Bridge extends homebridgeLib.AccessoryDelegate {
this.service.update(response.body)
response = await this.client.list()
for (const device of response.body) {
this.debug('device: %j', device)
if (device.firmwareVersion == null) { // Issue 93.
continue
}
const id = device.nukiId.toString(16).toUpperCase()
if (!this.platform.isWhitelisted(id)) {
continue
}
switch (device.deviceType) {
case NbClient.DeviceTypes.SMARTLOCK:
case NbClient.DeviceTypes.SMARTDOOR:
case NbClient.DeviceTypes.SMARTLOCK3:
if (this.smartLocks[id] == null) {
this.addSmartLock(id, {
id,
name: device.name,
firmware: device.firmwareVersion,
deviceType: device.deviceType
})
}
this.smartLocks[id].values.firmware = device.firmwareVersion
this.smartLocks[id].context.deviceType = device.deviceType
if (device.lastKnownState == null) {
this.smartLocks[id].warn('no last known state')
continue
}
this.smartLocks[id].update(device.lastKnownState)
if (
device.lastKnownState.doorsensorState != null &&
device.lastKnownState.doorsensorState !== NbClient.DoorSensorStates.DEACTIVATED
) {
if (this.doorSensors[id + '-S'] == null) {
this.addDoorSensor(id + '-S', {
id: id + '-S',
name: device.name + ' Sensor',
firmware: device.firmwareVersion,
deviceType: device.deviceType
})
try {
this.debug('device: %j', device)
if (device.firmwareVersion == null) { // Issue 93.
continue
}
const id = device.nukiId.toString(16).toUpperCase()
if (!this.platform.isWhitelisted(id)) {
continue
}
switch (device.deviceType) {
case NbClient.DeviceTypes.SMARTLOCK:
case NbClient.DeviceTypes.SMARTDOOR:
case NbClient.DeviceTypes.SMARTLOCK3:
if (device.lastKnownState == null) {
this.warn('%s: no last known state', id)
continue
}
if (this.smartLocks[id] == null) {
this.addSmartLock(id, { id, device })
}
this.smartLocks[id].context.device = device
this.smartLocks[id].update(device.lastKnownState)
if (
device.lastKnownState.doorsensorState != null &&
device.lastKnownState.doorsensorState !== NbClient.DoorSensorStates.DEACTIVATED
) {
if (this.doorSensors[id + '-S'] == null) {
this.addDoorSensor(id + '-S', { id: id + '-S', device })
}
this.doorSensors[id + '-S'].context.device = device
this.doorSensors[id + '-S'].update(device.lastKnownState)
} else if (this.doorSensors[id + '-S'] != null) {
this.doorSensors[id + '-S'].destroy()
delete this.doorSensors[id + '-S']
}
this.doorSensors[id + '-S'].values.firmware = device.firmwareVersion
this.doorSensors[id + '-S'].context.deviceType = device.deviceType
this.doorSensors[id + '-S'].update(device.lastKnownState)
} else if (this.doorSensors[id + '-S'] != null) {
this.doorSensors[id + '-S'].destroy()
delete this.doorSensors[id + '-S']
}
break
case NbClient.DeviceTypes.OPENER:
if (this.openers[id] == null) {
this.addOpener(id, {
id,
name: device.name,
firmware: device.firmwareVersion,
deviceType: device.deviceType
})
}
this.openers[id].values.firmware = device.firmwareVersion
this.openers[id].context.deviceType = device.deviceType
if (device.lastKnownState == null) {
this.openers[id].warn('no last known state')
continue
}
this.openers[id].update(device.lastKnownState)
break
default:
break
break
case NbClient.DeviceTypes.OPENER:
if (device.lastKnownState == null) {
this.warn('%s: no last known state', id)
continue
}
if (this.openers[id] == null) {
this.addOpener(id, { id, device })
}
this.openers[id].context.device = device
this.openers[id].update(device.lastKnownState)
break
default:
break
}
} catch (error) {
this.warn('heartbeat error: %s', error)
}
}
} catch (error) {
Expand All @@ -322,14 +305,24 @@ class Bridge extends homebridgeLib.AccessoryDelegate {

class SmartLock extends NbAccessory {
constructor (bridge, params) {
params.category = bridge.Accessory.Categories.DOOR_LOCK
params.model = NbClient.modelName(params.deviceType, params.firmware)
super(bridge, params)
super(bridge, {
id: params.id,
name: params.device.name,
device: params.device,
category: bridge.Accessory.Categories.DOOR_LOCK,
model: NbClient.modelName(params.device.deviceType, params.device.firmwareVersion)
})
this.service = new NbService.SmartLock(this)
if (this.platform.config.latch) {
this.latchService = new NbService.Latch(this)
}
this.batteryService = new homebridgeLib.ServiceDelegate.Battery(this)
this.batteryService = new homebridgeLib.ServiceDelegate.Battery(this, {
batteryLevel: params.device.lastKnownState.batteryChargeState,
chargingState: params.device.lastKnownState.batteryCharging,
statusLowBattery: params.device.lastKnownState.batteryCritical
? this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_LOW
: this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_NORMAL
})
}

update (state) {
Expand All @@ -340,6 +333,11 @@ class SmartLock extends NbAccessory {
if (state.batteryChargeState) {
this.batteryService.values.batteryLevel = state.batteryChargeState
}
if (state.batteryCharging != null) {
this.batteryService.values.chargingState = state.batteryCharging
? this.Characteristics.hap.ChargingState.CHARGING
: this.Characteristics.hap.ChargingState.NOT_CHARGING
}
if (state.batteryCritical != null) {
this.batteryService.values.statusLowBattery = state.batteryCritical
? this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_LOW
Expand All @@ -361,8 +359,21 @@ class DoorSensor extends NbAccessory {
constructor (bridge, params) {
params.category = bridge.Accessory.Categories.DOOR
params.model = 'Door Sensor'
super(bridge, params)
super(bridge, {
id: params.id,
name: params.device.name + ' Sensor',
device: params.device,
category: bridge.Accessory.Categories.DOOR,
model: 'Door Sensor'
})
this.service = new NbService.DoorSensor(this)
if (params.device.lastKnownState.doorsensorBatteryCritical) {
this.batteryService = new homebridgeLib.ServiceDelegate.Battery(this, {
statusLowBattery: params.device.lastKnownState.doorsensorBatteryCritical
? this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_LOW
: this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_NORMAL
})
}
this.historyService = new homebridgeLib.ServiceDelegate.History(this, {
contactDelegate: this.service.characteristicDelegate('contact'),
lastContactDelegate: this.service.characteristicDelegate('lastActivation'),
Expand All @@ -372,6 +383,11 @@ class DoorSensor extends NbAccessory {

update (state) {
this.service.update(state)
if (state.doorsensorBatteryCritical != null) {
this.batteryService.values.statusLowBattery = state.doorsensorBatteryCritical
? this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_LOW
: this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_NORMAL
}
}

async identify () {
Expand All @@ -387,26 +403,30 @@ class DoorSensor extends NbAccessory {
class Opener extends NbAccessory {
constructor (bridge, params) {
params.category = bridge.Accessory.Categories.DOOR_LOCK
params.model = NbClient.modelName(params.deviceType, params.firmware)
super(bridge, params)
params.model = NbClient.modelName(params.device.deviceType, params.device.firmwareVersion)
super(bridge, {
id: params.id,
name: params.device.name,
device: params.device,
category: bridge.Accessory.Categories.DOOR_LOCK,
model: NbClient.modelName(params.device.deviceType, params.device.firmwareVersion)
})
this.openerService = new NbService.Opener(this)
this.doorBellService = new NbService.DoorBell(this)
this.batteryService = new homebridgeLib.ServiceDelegate.Battery(this)
this.batteryService = new homebridgeLib.ServiceDelegate.Battery(this, {
statusLowBattery: params.device.lastKnownState.doorsensorBatteryCritical
? this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_LOW
: this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_NORMAL
})
}

update (state) {
this.doorBellService.update(state)
this.openerService.update(state)
if (state.batteryCritical != null) {
if (state.batteryCritical) {
this.batteryService.values.statusLowBattery =
this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_LOW
this.batteryService.values.batteryLevel = 10
} else {
this.batteryService.values.statusLowBattery =
this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_NORMAL
this.batteryService.values.batteryLevel = 90
}
this.batteryService.values.statusLowBattery = state.batteryCritical
? this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_LOW
: this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_NORMAL
}
}

Expand Down

0 comments on commit 4c513b5

Please sign in to comment.