Closed Pingbo closed 4 years ago
I quickly scanned through the documentation, does this mean the field offset of the fields starting from:
Will have to change? What is exactly now breaking? Can you show me the new payload (Did not update my Nuki's yet)?
Yep exactly, here some Infos from my nuki with updated FW:
payload = 020103e4070a0c08150a00007c0e00020300020000
Output from brigde:
Nuki_STATES Nuki Status: Door Mode Lock Status: Locked Trigger: 03 Current Time: 12-10-2020 08:21:10 Time Offset: 0 Critical Battery: 7C Doorsensor State: door closed
Battery displayed in App: 62% So my Assumtion is that 7C hex is 01111100 binary The first flag is battery criticality, 2-7 is the Percentage... In my case 111110 is 62%
Currently i have no idea how to solve this in a elegant way
Perhaps something like this: (But this seems complicated)
self.criticalBattery = bin(int(payload[24:26], 16))[2:].zfill(8)
if self.criticalBattery[:1] == '0':
self.criticalBattery = 'OK'
elif self.criticalBattery[:1] == '1':
self.criticalBattery = 'Critical'
self.BatteryPercentage = int(bin(int(payload[24:26], 16))[2:].zfill(8)[1:7].zfill(8),2)
self.criticalBattery reads out the hex, formats to binary and gets the first bit self.BatteryPercentage reads out the hex, formats to binary, gets 2-7 bit and formats it to decimal
Or a little bit cleaner:
self.Battery = bin(int(payload[24:26], 16))[2:].zfill(8)
if self.Battery[:1] == '0':
self.criticalBattery = 'OK'
elif self.Battery[:1] == '1':
self.criticalBattery = 'Critical'
self.BatteryPercentage = int(self.Battery[1:7],2)
And for sure edit the print:
def show(self):
return "Nuki_STATES\n\tNuki Status: %s\n\tLock Status: %s\n\tTrigger: %s\n\tCurrent Time: %s\n\tTime Offset: %s\n\tCritical Battery: %s\n\tBattery Percentage: %d\n\tDoorsensor State: %s" % (self.nukiState,self.lockState,self.trigger,self.currentTime,self.timeOffset,self.criticalBattery,self.BatteryPercentage,self.Doorsensor)
I assume that Battery Percentage: %d will need the %d, but i haven't tested it yet
Can you check your actual battery percentage in the app? It's not charging and not critical I guess
The documentation states it's in steps of 2 so that's why I'm surprised that the decimal number is 62
In your code, aren't you missing the charging flag? Shouldn't it be 2:7 instead of 1:7?
Otherwise, looks good! And since we are using Python 3.7, we can use: f'{0x7C:0>8b}' to get a binary string I think...
Btw. 01111100, from right to left means 011111 is the percentage, that's 31 in decimal, multiplied by 2, is your percentage. So we should also multiply it as stated in the docs.
Seems like i'm wrong, cause 6Bit (2-7) are not able to show 100%....
I now have tested with other Batteries:
payload = 020100e4070a0c0923020000b00e00000000020000
Nuki_STATES
Nuki Status: Door Mode
Lock Status: Locked
Trigger: Bluetooth
Current Time: 12-10-2020 09:35:02
Time Offset: 0
Critical Battery: B0
Doorsensor State: door closed
So this gets me to the assumtion the the Percantage are the first 7 Bit, because: B0 = 10110000 1011000 = 88 Percentage in App = 88
Same counts for the example with 62%: 7c = 01111100 0111110 = 62
So the code will look like this:
self.Battery = bin(int(payload[24:26], 16))[2:].zfill(8)
if self.Battery[??????????] == '0':
self.criticalBattery = 'OK'
elif self.Battery[??????????] == '1':
self.criticalBattery = 'Critical'
self.BatteryPercentage = int(self.Battery[:7],2)
Currently i have no almost empty Batteries, so i have no clue where the criticalBattery is....
For Charging and Critical Battery Flag i have no idea whats going on here. I'm sadly not able to test it. Charging is probably only for the Nuki Power Pack?
I've already tested a little bit with f-strings, but i wasn't able to find a good solution. But if you have a good one, i'm fine with it :)
Since it's binary, the first bit is the most right one.
So: 10110000
Last zero is battery critical Second to last (0) is charging.
The first 6 bits are 44 so 88.
100 procent battery would be 110010 (50 decimal)
God, you are so right.... the first bit is the right one not the left.... This means for 88%: B0 = 10110000 101100 = 44 * 2 = 88
7c = 01111100 011111 = 31 * 2 = 62
Code with Charging Flag without f-strings:
self.Battery = bin(int(payload[24:26], 16))[2:].zfill(8)
if self.Battery[7:8] == '0':
self.criticalBattery = 'OK'
elif self.Battery[7:8] == '1':
self.criticalBattery = 'Critical'
if self.Battery[6:7] == '0':
self.chargingBattery = 'Not Charging'
elif self.Battery[6:7] == '1':
self.chargingBattery = 'Charging'
self.BatteryPercentage = int(self.Battery[:6],2)*2
And the print function:
def show(self):
return "Nuki_STATES\n\tNuki Status: %s\n\tLock Status: %s\n\tTrigger: %s\n\tCurrent Time: %s\n\tTime Offset: %s\n\tCritical Battery: %s\n\tCharging Battery: %s\n\tBattery Percentage: %d\n\tDoorsensor State: %s" % (self.nukiState,self.lockState,self.trigger,self.currentTime,self.timeOffset,self.criticalBattery,self.chargingBattery,self.BatteryPercentage,self.Doorsensor)
This should be it, can you test this code?
Yes i able to test it, Output looks good:
Nuki State Request sent: Nuki_REQ
Payload: Nuki_STATES
response received:
payload = 020100e4070a0c0a1a220000b00e00000000020000
Nuki_STATES
Nuki Status: Door Mode
Lock Status: Locked
Trigger: Bluetooth
Current Time: 12-10-2020 10:26:34
Time Offset: 0
Critical Battery: OK
Charging Battery: Not Charging
Battery Percentage: 88
Doorsensor State: door closed
Perhaps you can open a new Branch for the "old" FW and update the master? That people can use the right one for their needs
I have checked in the code. Also verified if the change works with firmware 2.7 and it does not break, so I just pushed to master.
Also added retry logic for the state endpoint.
With the new Firmware, Nuki introduced the Battery Percentage Fields:
https://developer.nuki.io/page/nuki-smart-lock-api-220/2#heading--keyturner-states
This breaks the state function, so it need some adjustments to read Out the required fields for Battery criticality and perhaps the Battery Percentage can be implemented as well