Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add ZGP (continue of PR #519) #656

Closed
wants to merge 16 commits into from
Closed

[WIP] Add ZGP (continue of PR #519) #656

wants to merge 16 commits into from

Conversation

zoic21
Copy link

@zoic21 zoic21 commented Feb 1, 2021

No description provided.

@Hedda
Copy link
Contributor

Hedda commented Feb 2, 2021

FYI, for reference to new devs; this replaces pull request #519 for "Zigbee Green Power" (ZGP) but that still has relevant discussions.

Testers can see instructions on "testing new releases" here -> https://github.com/zigpy/zigpy/blob/dev/CONTRIBUTING.md

It is the "dev" branch here that needs regression testing and reviews before merger -> https://github.com/jeedom/zigpy

PS: Zigbee Green Power (a.k.a. Zigbee GreenPower) supporting devices are discussed in #341 which contains a list of ZGP devices.

@zoic21
Copy link
Author

zoic21 commented Feb 4, 2021

@Hedda thank I will look at it

Can someone can test with this code if all it's ok ? No side effect. If it I think we can merge this first step (after I fix coveralls).

@Shulyaka
Copy link
Contributor

Shulyaka commented Feb 6, 2021

Hi!

I'm using XBee as a coordinator and it does not have a ZGP cluster. However I have a Philips Hue bulb that does have it.
Would it be possible to configure the hue light as a ZGP proxy for my ZGP switches?
Right now I can't even get any GreenPowerProxy attribute value

@Hedda
Copy link
Contributor

Hedda commented Feb 9, 2021

I'm using XBee as a coordinator and it does not have a ZGP cluster.

I do not have XBee hardware myself but wonder which exact XBee hardware and Zigbee firmware you have/use with zigpy?

Does even the very latest XBee Zigbee stack still not have Zigbee Green Power support at all?

Semi-new Zigbee PRO should support the older Green Power Specification v1.0 while Zigbee 3.0 specification supports ZGP v2.0

Have not checked but I thought that there was a Zigbee 3.0 stack for XBee?

I could not find any changelogs online specifically for Zigbee however it sounds as release notes should be available in XCTU?

https://www.digi.com/support/knowledge-base/xbee-firmware-revision-history-and-identification

https://www.digi.com/products/embedded-systems/digi-xbee/digi-xbee-tools/xctu

@Shulyaka
Copy link
Contributor

Shulyaka commented Feb 9, 2021

No, they don't explicitly support it. I hope that unsupported messages will be passed through to zigpy but couldn't get one yet. The question is whether I could get it working in theory. Currently I can't even get what to start with. I think I need to configure the bulb to be proxy, I think my next step would be to get a zigbee sniffer and monitor how the hue bridge itself does that.

@Adminiuga
Copy link
Collaborator

@Shulyaka are you trying it on XBee 3 or on S2C? AFAIK under the hood XBees are running on the silabs chip and application, so question is whether they've compiled the app with ZGP support + whether they allow passing of the ZGP messages from silabs to XBee protocol handlers.
Have you tried changing the AT registers for the endpoint and profiles to the one of ZGPs? Although I'm skeptical it would work.

I can send you one of pre-flashed EBytes modules, so we don't have to support XBee coordinators anymore 😄 I think it is just you and Tube, but Tube already has switched to the dark side and building a silabs coordinator 🤣

@tube0013
Copy link
Contributor

tube0013 commented Feb 9, 2021

Haha. My network is on an ebyte right now.. the super charged efr32s are in waiting.

I have an xbee as a router from back when it was one of the proven xiaomi friendly routers.image

@MattWestb
Copy link
Contributor

Tube is needing one good receipt for cooking one EFR32 router firmware with ZGP proxy very soon for all new Silabs modules !!!

@Shulyaka
Copy link
Contributor

Shulyaka commented Feb 9, 2021

@Shulyaka are you trying it on XBee 3 or on S2C? AFAIK under the hood XBees are running on the silabs chip and application, so question is whether they've compiled the app with ZGP support + whether they allow passing of the ZGP messages from silabs to XBee protocol handlers.
Have you tried changing the AT registers for the endpoint and profiles to the one of ZGPs? Although I'm skeptical it would work.

I can send you one of pre-flashed EBytes modules, so we don't have to support XBee coordinators anymore 😄 I think it is just you and Tube, but Tube already has switched to the dark side and building a silabs coordinator 🤣

I'm using XBee3. No, I haven't tried changing the endpoint, thanks for the hint)
You don't have to support xbee as coordinator just for me, I can find my way around. I chose it because I use another xbee to control my DIY humidifier, and the quirck uses remote_at command that is only available to xbee coordinators. But I think it is possible to implement it for other coordinators as well.
Also, I can connect it to internal UART and hide inside my router leaving USB ports free. And another consideration: with the latest firmware it is possible to copy the encryption keys to other modules, and I think may be I could use it to implement a failover to another HA instance in the future:)
As for this issue, I think I just lack some understanding on how ZGP works, sniffing some traffic from the real hue bridge will help me get educated.

@Hedda
Copy link
Contributor

Hedda commented Feb 10, 2021

I chose it because I use another xbee to control my DIY humidifier, and the quirck uses remote_at command that is only available to xbee coordinators. But I think it is possible to implement it for other coordinators as well.

Telegesis ETRX3 Series also ships Silicon Labs AT command interface R3xx firmware and com.zsmartsystems.zigbee library (used by OpenHAB amonst others) supports TG ETRXn AT commands protocol over serial interface ("currently implemented against R309C"):

https://github.com/zsmartsystems/com.zsmartsystems.zigbee/blob/master/README.md

https://www.silabs.com/documents/public/reference-manuals/TG-ETRXn-Commands.pdf

https://www.silabs.com/documents/public/application-notes/TG-APP-0024r3-UsingR3xxFirmwareinaHomeAutomationNetwork.pdf

another consideration: with the latest firmware it is possible to copy the encryption keys to other modules, and I think may be I could use it to implement a failover to another HA instance in the future :)

@Shulyaka Are you following the discussions in #557 (as well of that in Koenkk/zigbee-herdsman#303) about backup and restore?

Maybe talk with puddly/castorw about https://github.com/zigpy/open-coordinator-backup/ tools for failover of Home Assistant?

@Hedda
Copy link
Contributor

Hedda commented Sep 30, 2021

Is PR zigpy/zha-device-handlers#1048 for zha-device-handlers/zha-quirks in any way related to this [WIP] ZGP PR or zigpy?

@MattWestb
Copy link
Contributor

Nop its only for ZHA shall loading the quirk and the ZGP proxy is working in the background if the router is having it.

You dont need / can not configuring the ZGP cluster is one "repeater" for the ZGP framed and is working autonomous in the router device.

@eriknn
Copy link

eriknn commented Oct 20, 2021

Is this project dead?

@Munken
Copy link

Munken commented Oct 20, 2021

@eriknn I've been running this with custom_deps since June without issues,
but I've given up on getting the maintainers to review so it can be merged.

I've been using it with this custom device handler:
zigpy/zha-device-handlers@dev...Munken:sunricher

@puddly
Copy link
Collaborator

puddly commented Oct 20, 2021

I've given up on getting the maintainers to review so it can be merged.

A ton of work is being done in the background to make a proper rewrite of this PR possible but with the few core contributors juggling various other improvements and this being a side project for all of us, it may take some time:

@Munken
Copy link

Munken commented Oct 22, 2021

@puddly fair point and I'm very happy to hear that.
However, none of that was communicated in this PR which is why I had such a pessimistic view on things.

@AlSa-Her
Copy link

Hey,
I just moved from zigbee2mqtt to ZHA (during a switch from node-red to home assistant) a couple of weeks back and am loving it! First off, I would like to express my appreciation to all developers!
I would love to be able to use the "senic gira friends of hue" wall switches, which obviously use ZGP, with the new setup. So I am excited to read this thread and hopefully see this happen soon (fingers crossed) :)
So, in general, this is just meant as a thank you for the work 👍

@TPMunster
Copy link

Yes it is for a four button remote.

image

Hi @Munken - how did you add this device to HA via ZHA? And is it in fact currently working?
Do I need to have beta release implemented or is the quirk already released?

Thank you in advance 🙏

@Munken
Copy link

Munken commented Nov 26, 2021

@TPMunster none of the changes has been upstreamed yet since I was waiting on approval of the zigpy changes first.
I were running my own custom branch of bellows, zigpy and zha-device-handlers.

The branches are here:
https://github.com/zigpy/zha-device-handlers/compare/dev...Munken:sunricher-multibutton?expand=1
https://github.com/zigpy/zigpy/compare/dev...Munken:commandid?expand=1
https://github.com/zigpy/bellows/compare/dev...Munken:munk?expand=1

Word of caution, I've since moved to Zigbee2MQTT so all of the above are stale forks that will not be maintained.

@TPMunster
Copy link

@Hedda did you ever get the ZGP switches working via ZHA? ✌️

@TPMunster
Copy link

Thank you @Munken , I will give it a go. Even though I'm pretty newb in all this custom stuff ✌️

@Munken
Copy link

Munken commented Nov 27, 2021

@TPMunster my impression is that only I and @zoic21 got this up and running.

Also note that this implementation only performs direct communication between the ZGP button and the root router.
Depending on the size of your place that might be problematic.

My suggestion would be to use Z2M for ZGP until ZGP is fully supported by zigpy.

@Hedda
Copy link
Contributor

Hedda commented Dec 20, 2021

@zoic21 (and @TPMunster) Any updates on getting this rebased and trying to get it ready for re-review and merger again?

I understand that Jeedom have now used their fork https://github.com/jeedom/zigpy with this ZGP feature enabled in their official plugin #725 for a relativly long time now so would think it should also be in their interest to get this merged into upstream zigpy?

@zoic21
Copy link
Author

zoic21 commented Dec 20, 2021

Hello,

I already rebase it 2 times and merge nerver comming... I understand my code is not good enough to be integrated into zigpy.

For information we don't use a fork for jeedom, I juste patch bellow after installation :

--- application.py      2021-05-18 09:51:36.011928845 +0200
+++ /usr/local/lib/python3.7/dist-packages/bellows/zigbee/application.py        2021-05-18 09:52:19.924839236 +0200
@@ -230,6 +230,8 @@
             self._handle_reset_request(*args)
         elif frame_name == "idConflictHandler":
             self._handle_id_conflict(*args)
+        elif frame_name == "gpepIncomingMessageHandler":
+            self.listener_event("zgp_frame", 'bellows',*args)

     def _handle_frame(
         self,

And

--- /usr/local/lib/python3.7/dist-packages/bellows/ezsp/v8/commands.py  2021-03-18 09:34:42.322028636 +0100
+++ commands.py 2021-05-04 17:46:55.921831239 +0200
@@ -631,16 +631,15 @@
             t.EmberStatus,
             t.uint8_t,
             t.uint8_t,
-            t.EmberGpAddress,
-            t.EmberGpSecurityLevel,
-            t.EmberGpKeyType,
-            t.Bool,
-            t.Bool,
+            t.uint8_t,
+            t.EmberEUI64,
+            t.uint32_t,
+            t.uint8_t,
             t.uint32_t,
             t.uint8_t,
             t.uint32_t,
-            t.EmberGpSinkListEntry,
-            t.LVBytes,
+            t.uint8_t,
+            t.LVBytes
         ),
     ),
     "gpProxyTableGetEntry": (

To redirect all zgp frame to listner that handle frame :

# This file is part of Jeedom.
#
# Jeedom is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Jeedom is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Jeedom. If not, see <http://www.gnu.org/licenses/>.

import sys
import logging
import os
import shared,utils
import json
import time
import zigpy
import zigpy.types as t
import zigpy.zdo as zdo


from Crypto.Cipher import AES
from Crypto.Util import Counter
from zigpy.zcl import Cluster, foundation

endpoint_id = 242
cluster_id = 0x0021
device_type = 0xA1E0

commands = {
	0x00: ("Identify", "CLUSTER_COMMAND", (), None, None, ()),
	0x10: ("Scene 0", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 0)),
	0x11: ("Scene 1","CLUSTER_COMMAND",(),0x0005,0x0001,(0,1,),),
	0x12: ("Scene 2", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 2)),
	0x13: ("Scene 3", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 3)),
	0x14: ("Scene 4", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 4)),
	0x15: ("Scene 5", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 5)),
	0x17: ("Scene 7", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 6)),
	0x16: ("Scene 6", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 7)),
	0x18: ("Scene 8", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 8)),
	0x19: ("Scene 9", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 9)),
	0x1A: ("Scene 10", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 10)),
	0x1B: ("Scene 11", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 11)),
	0x1C: ("Scene 12", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 12)),
	0x1D: ("Scene 13", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 13)),
	0x1E: ("Scene 14", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 14)),
	0x1F: ("Scene 15", "CLUSTER_COMMAND", (), 0x0005, 0x0001, (0, 15)),
	0x20: ("Off", "CLUSTER_COMMAND", (), 0x0006, 0x0000, ()),
	0x21: ("On", "CLUSTER_COMMAND", (), 0x0006, 0x0001, ()),
	0x22: ("Toggle", "CLUSTER_COMMAND", (), 0x0006, 0x0002, ()),
	0x23: ("Release", "CLUSTER_COMMAND", (), None, None, ()),
	0x30: ("Move Up", "CLUSTER_COMMAND", (t.uint8_t,), 0x0008, 0x0001, (1,)),
	0x31: ("Move Down", "CLUSTER_COMMAND", (t.uint8_t,), 0x0008, 0x0000, (0,)),
	0x32: ("Step Up","CLUSTER_COMMAND",(t.uint8_t, t.Optional(t.uint16_t)),0x0008,0x0002,(1,),),
	0x33: ("Step Down","CLUSTER_COMMAND",(t.uint8_t, t.Optional(t.uint16_t)),0x0008,0x0002,(0,),),
	0x34: ("Level Control/Stop", "CLUSTER_COMMAND", (), 0x0008, 0x0007, ()),
	0x35: ("Move Up (with On/Off)","CLUSTER_COMMAND",(t.uint8_t,),0x0008,0x0005,(1,),),
	0x36: ("Move Down (with On/Off)","CLUSTER_COMMAND",(t.uint8_t,),0x0008,0x0005,(0,),),
	0x37: ("Step Up (with On/Off)","CLUSTER_COMMAND",(t.uint8_t, t.Optional(t.uint16_t)),0x0008,0x0006,(1,),),
	0x38: ("Step Down (with On/Off)","CLUSTER_COMMAND",(t.uint8_t, t.Optional(t.uint16_t)),0x0008,0x0006,(0,),),
	0x40: ("Move Hue Stop", "CLUSTER_COMMAND", (), 0x0300, 0x0047, ()),
	0x41: ("Move Hue Up Color","CLUSTER_COMMAND",(t.uint8_t,),0x0300,0x0001,(1,),),
	0x42: ("Move Hue Down Color","CLUSTER_COMMAND",(t.uint8_t,),0x0300,0x0001,(0,),),
	0x43: ("Step Hue Up Color","CLUSTER_COMMAND",(t.uint8_t, t.Optional(t.uint16_t)),0x0300,0x0002,(1,),),
	0x44: ("Step Hue Down Color","CLUSTER_COMMAND",(t.uint8_t, t.Optional(t.uint16_t)),0x0300,0x0002,(0,),),
	0x46: ("Move Saturation Up","CLUSTER_COMMAND",(t.uint8_t,),0x0300,0x0004,(1,),),
	0x47: ("Move Saturation Down","CLUSTER_COMMAND",(t.uint8_t,),0x0300,0x0004,(0,),),
	0x48: ("Step Saturation Up","CLUSTER_COMMAND",(t.uint8_t,),0x0300,0x0005,(1,),),
	0x49: ("Step Saturation Down","CLUSTER_COMMAND",(t.uint8_t,),0x0300,0x0005,(0,),),
	0x4A: ("Move Color","CLUSTER_COMMAND",(t.uint16_t, t.uint16_t),0x0300,0x0008,(),),
	0x4B: ("Step Color","CLUSTER_COMMAND",(t.uint16_t, t.uint16_t, t.Optional(t.uint16_t)),0x0300,0x0009,(),),
	0x45: ("Move Saturation Stop", "CLUSTER_COMMAND", (), 0x0300, 0x0047, ()),
	0x50: ("Lock Door", "CLUSTER_COMMAND", (), 0x0101, 0x0000, ()),
	0x51: ("Unlock Door", "CLUSTER_COMMAND", (), 0x0101, 0x0001, ()),
	0x60: ("Press 1 of 1", "CLUSTER_COMMAND", (), None, None, ()),
	0x61: ("Release 1 of 1", "CLUSTER_COMMAND", (), None, None, ()),
	0x62: ("Press 1 of 2", "CLUSTER_COMMAND", (), None, None, ()),
	0x63: ("Release 1 of 2", "CLUSTER_COMMAND", (), None, None, ()),
	0x64: ("Press 2 of 2", "CLUSTER_COMMAND", (), None, None, ()),
	0x65: ("Release 2 of 2", "CLUSTER_COMMAND", (), None, None, ()),
	0x66: ("Short press 1 of 1", "CLUSTER_COMMAND", (), None, None, ()),
	0x67: ("Short press 1 of 2", "CLUSTER_COMMAND", (), None, None, ()),
	0x68: ("Short press 2 of 2", "CLUSTER_COMMAND", (), None, None, ()),
	0x69: ("Press", "CLUSTER_COMMAND", (t.uint8_t,), 0x0005, 0x0001, (0,)),
	0x6A: ("Release", "CLUSTER_COMMAND", (t.uint8_t,), None, None, ()),
}

devices = {
	0x00: ("Simple Generic 1-state Switch", [], [0x0006]),
	0x01: ("Simple Generic 2-state Switch", [], [0x0006]),
	0x02: ("On/Off Switch", [], [0x0005, 0x0006]),
	0x03: ("Level Control Switch", [], [0x0008]),
	0x04: ("Simple Sensor", [], []),
	0x05: ("Advanced Generic 1-state Switch", [], [0x0005, 0x0006]),
	0x06: ("Advanced Generic 2-state Switch", [], [0x0005, 0x0006]),
	0x07: ("On/Off Switch", [], [0x0005, 0x0006]),
	0x10: ("Color Dimmer Switch", [], [0x0300]),
	0x11: ("Light Sensor", [0x0400], []),
	0x12: ("Occupancy Sensor", [0x0406], []),
	0x20: ("Door Lock Controller", [], [0x0101]),
	0x30: ("Temperature Sensor", [0x0402], []),
	0x31: ("Pressure Sensor", [0x0403], []),
	0x32: ("Flow Sensor", [0x0404], []),
	0x33: ("Indoor Environment Sensor", [], []),
}

def create_device(ieee, type=None, remoteCommissioning=False):
	application = shared.ZIGPY
	if ieee in application.devices:
		return application.devices[ieee]
	gateway = shared.ZIGPY.get_device(nwk=0)
	if not endpoint_id in gateway.endpoints:
		ep = gateway.add_endpoint(endpoint_id)
		ep.status =  zigpy.endpoint.Status.ZDO_INIT
		ep.profile_id = zigpy.profiles.zha.PROFILE_ID
		ep.device_type = device_type
		ep.add_output_cluster(cluster_id)
	if not remoteCommissioning and (0x9997 not in gateway.endpoints[endpoint_id].out_clusters[cluster_id]._attr_cache or gateway.endpoints[endpoint_id].out_clusters[cluster_id]._attr_cache[0x9997] < time.time()):
		logging.info("[zgp.create_device] Not in permit joining mode and not in remoteCommissioning")
		return None
	logging.info("[zgp.create_device] Device %s not found, create it", ieee)
	nwk = 32766
	for i in range(32766, 65535):
		nwk = i 
		try:
			shared.ZIGPY.get_device(nwk=i)
		except KeyError:
			break
	dev = application.add_device(ieee, nwk)
	dev.status = zigpy.device.Status.ENDPOINTS_INIT
	dev._skip_configuration = True
	dev.node_desc = zdo.types.NodeDescriptor(2, 64, 128, 4174, 82, 82, 0, 82, 0)
	ep = dev.add_endpoint(1)
	ep.status = zigpy.endpoint.Status.ZDO_INIT
	ep.profile_id = zigpy.profiles.zha.PROFILE_ID
	ep.device_type = device_type
	application.device_initialized(dev)
	ep.add_input_cluster(zigpy.zcl.clusters.general.Basic.cluster_id)
	ep.in_clusters[zigpy.zcl.clusters.general.Basic.cluster_id]._update_attribute(0x0004, "GreenPower")
	in_clusters = None
	out_clusters = None
	if type is not None and type in devices:
		name, in_clusters, out_clusters = devices[type]
		ep.in_clusters[zigpy.zcl.clusters.general.Basic.cluster_id]._update_attribute(0x0005, name)
		for id in in_clusters:
			logging.info("[zgp.create_device] Add input cluster id %s on device %s", id, ieee)
			ep.add_input_cluster(id)
		for id in out_clusters:
			logging.info("[zgp.create_device] Add output cluster id %s on device %s", id, ieee)
			ep.add_output_cluster(id)
	else:
		ep.in_clusters[zigpy.zcl.clusters.general.Basic.cluster_id]._update_attribute(0x0005, "GreenPowerDevice")
	ep = dev.add_endpoint(endpoint_id)
	ep.status = zigpy.endpoint.Status.ZDO_INIT
	ep.profile_id = zigpy.profiles.zha.PROFILE_ID
	ep.device_type = device_type
	ep.add_input_cluster(cluster_id)
	return dev

def handle_notification(ieee, header, counter, command_id, payload, payload_length, mic):
	application = shared.ZIGPY
	if ieee not in application.devices:
		logging.info("[zgp.handle_notification] Unkwonw device : %s try to create it if allow", ieee)
		if create_device(ieee) is None:
			return
	if command_id not in commands:
		logging.info("[zgp.handle_notification] Unhandled command_id : %s", command_id)
		return
	expected_mic = calcul_mic(ieee,header,counter,command_id.to_bytes(1, "little")+ payload.to_bytes(payload_length, "little"),payload_length + 1,)
	if expected_mic is not None :
		logging.info("[zgp.handle_notification] Mic : %s, expected mic %s : OK", hex(mic), hex(expected_mic))
	if expected_mic is not None and expected_mic != mic:
		logging.info("[zgp.handle_notification] Wrong mic : %s, expected mic %s, ignore frame", hex(mic), hex(expected_mic))
		return
	(command,type,schema,clusterid,zcl_command_id,value) = commands[command_id]
	try:
		payload, _ = t.deserialize(payload.to_bytes(payload_length, "little"), schema)
	except Exception as e:
		payload = ()
		pass
	logging.info("[zgp.handle_notification] Green power frame ieee : %s, command_id : %s, payload : %s,counter : %s",ieee,command_id,payload,counter)
	value = value + tuple(payload)
	dev = application.devices[ieee]
	if counter is not None:
		attributes = dev.endpoints[endpoint_id].in_clusters[cluster_id]._attr_cache
		if 0x9999 in attributes and attributes[0x9999] >= counter:
			logging.info("[zgp.handle_notification] Already get this frame counter,I ignoring it")
			return
		attributes[0x9999] = counter
	if clusterid is not None and type == "CLUSTER_COMMAND":
		if clusterid not in dev.endpoints[1].out_clusters:
			dev.endpoints[1].add_output_cluster(clusterid)
			application.device_initialized(dev)
		dev.endpoints[1].out_clusters[clusterid].handle_message(foundation.ZCLHeader.cluster(application.get_sequence(), zcl_command_id),value)

def handle_message(data):
	application = shared.ZIGPY
	data = data[0]
	if data[0] == 12 and data[5] == 224:
		ieee = t.EUI64(data[1:5] + data[1:5])
		type = data[6]
		create_device(application,ieee, type)
		return
	payload = ()
	ieee = t.EUI64(data[2:6] + data[2:6])
	counter = int.from_bytes(data[6:10], byteorder="little")
	command_id = data[10]
	payload_length = len(data[11:-4])
	payload = int.from_bytes(data[11:-4], byteorder="little")
	mic = int.from_bytes(data[-4:], byteorder="little")
	header = int.from_bytes(data[0:2], byteorder="little")
	handle_notification(application,ieee, header, counter, command_id, payload, payload_length, mic)

def calcul_mic(ieee, header, counter, payload, payload_length):
	application = shared.ZIGPY
	if ieee not in application.devices:
		return None
	dev = application.devices[ieee]
	if (0x9998 not in dev.endpoints[endpoint_id].in_clusters[cluster_id]._attr_cache):
		return None
	src_id = bytearray(ieee[0:4])
	if not isinstance(header, (bytes)):
		header = header.to_bytes(2, "little")
	if not isinstance(counter, (bytes)):
		counter = counter.to_bytes(4, "little")
	if not isinstance(payload, (bytes)):
		payload = payload.to_bytes(payload_length, "little")
	logging.info("[zgp.calcul_mic] Calcul mic of green power frame for %s on header : 0x%s, src_id : 0x%s, counter : 0x%s, payload : 0x%s, payload length : %s",ieee,header.hex(),src_id.hex(),counter.hex(),payload.hex(),payload_length,)
	key = dev.endpoints[endpoint_id].in_clusters[cluster_id]._attr_cache[0x9998]
	nonce = src_id + src_id + counter + (0x05).to_bytes(1, "little")
	header = header + src_id + counter
	a = header + payload
	La = len(a).to_bytes(2, "big")
	AddAuthData = La + a
	AddAuthData += (0x00).to_bytes(1, "little") * (16 - len(AddAuthData))
	B0 = (0x49).to_bytes(1, "little") + nonce
	B0 += (0x00).to_bytes(1, "little") * (16 - len(B0))
	B1 = AddAuthData
	X0 = (0x00000000000000000000000000000000).to_bytes(16, "big")
	cipher = AES.new(key, AES.MODE_CBC, B0)
	X1 = cipher.encrypt(X0)
	cipher = AES.new(key, AES.MODE_CBC, B1)
	X2 = cipher.encrypt(X1)
	A0 = (0x01).to_bytes(1, "little") + nonce + (0x0000).to_bytes(2, "big")
	cipher = AES.new(key,AES.MODE_CTR,counter=Counter.new(128, initial_value=int.from_bytes(A0, byteorder="big")))
	return int.from_bytes(cipher.encrypt(X2[0:4]), byteorder="little")
	
def setKey(device, key):
	if key is None:
		logging.info("[zgp.setKey] Remove key for device "+str(device.ieee))
		del device.endpoints[endpoint_id].in_clusters[cluster_id]._attr_cache[0x9998]
		return
	if not isinstance(key, (bytes)):
		key = key.to_bytes(16, "big")
	logging.info("[zgp.setKey] Set key for device "+str(device.ieee)+' to '+str(key))
	device.endpoints[endpoint_id].in_clusters[cluster_id]._update_attribute(0x9998, key)
	
async def permit(time_s=60):
	assert 0 <= time_s <= 254
	application = shared.ZIGPY
	logging.info("[zgp.permit] Permit green power pairing for %s s", time_s)
	application.devices[application._ieee].endpoints[endpoint_id].out_clusters[cluster_id]._attr_cache[0x9997] = int(time.time() + time_s)
	return

It's not clean code but it's working.

@HarvsG
Copy link

HarvsG commented Jan 29, 2022

I've given up on getting the maintainers to review so it can be merged.

A ton of work is being done in the background to make a proper rewrite of this PR possible but with the few core contributors juggling various other improvements and this being a side project for all of us, it may take some time:

Great to see the progress

@dontinelli
Copy link

I've given up on getting the maintainers to review so it can be merged.

A ton of work is being done in the background to make a proper rewrite of this PR possible but with the few core contributors juggling various other improvements and this being a side project for all of us, it may take some time:

* [x]  Allowing bitfield-heavy ZGP structs and enums to be defined directly, without the need for as many opaque bitwise operations ([Add support for bitfields to Structs #669](https://github.com/zigpy/zigpy/pull/669))

* [x]  Supporting arbitrary database schema migrations, allowing the `devices` table to be extended to support ZGP devices (or adding a new table for them) ([Migrate appdb to versioned tables to support zigpy upgrades/downgrades #711](https://github.com/zigpy/zigpy/pull/711))

* [x]  High-level network state representation ([ControllerApplication State class and counters #787](https://github.com/zigpy/zigpy/pull/787))

@puddly : Any news on the progress of the above and/or the implementation of ZGP? It seems that the last activity on all PR dates back quite some time (i.e. summer/fall 2021). Would be interesting to hear if ZGP will be available in ZHA in the foreseeable future at all. I appreciate that contributors work in their spare time on the project and that not all feature requests can be implemented at once. Even more it would be helpful to understand where the current focus of development lies.

@Hedda
Copy link
Contributor

Hedda commented Mar 9, 2022

I've given up on getting the maintainers to review so it can be merged.

A ton of work is being done in the background to make a proper rewrite of this PR possible but with the few core contributors juggling various other improvements and this being a side project for all of us, it may take some time:

* [x]  Allowing bitfield-heavy ZGP structs and enums to be defined directly, without the need for as many opaque bitwise operations ([Add support for bitfields to Structs #669](https://github.com/zigpy/zigpy/pull/669))

* [x]  Supporting arbitrary database schema migrations, allowing the `devices` table to be extended to support ZGP devices (or adding a new table for them) ([Migrate appdb to versioned tables to support zigpy upgrades/downgrades #711](https://github.com/zigpy/zigpy/pull/711))

* [x]  High-level network state representation ([ControllerApplication State class and counters #787](https://github.com/zigpy/zigpy/pull/787))

@puddly : Any news on the progress of the above and/or the implementation of ZGP? It seems that the last activity on all PR dates back quite some time (i.e. summer/fall 2021). Would be interesting to hear if ZGP will be available in ZHA in the foreseeable future at all. I appreciate that contributors work in their spare time on the project and that not all feature requests can be implemented at once. Even more it would be helpful to understand where the current focus of development lies.

Not sure if any of the other recently merged pull requests directly or indirectly will also help make a rewrite of this PR possible(?), but know that, after update to ZCL v7 specification, the recent focus has been on the New radio API (and it is not related to ZGP).

PS: One thing that could potentially help increase interest in this could be to donate Zigbee Green Power devices to developers like puddly and Adminiuga as that might pique their interest a little more if they actually owned certified ZGP devices themselves.

@Grandma-Betty
Copy link

Grandma-Betty commented May 1, 2022

Well, if this is still an important option and if any of you devs is interested in this, I would donate an EnOcean PTM 215Z device. Just tell me your shipping address and I will order one for you. I would fully donate this device if it helps to make it work in Home Assistant's ZHA integration in the future.

@github-actions
Copy link

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days. Thank you for your contributions.

@github-actions github-actions bot added the stale label Oct 30, 2022
@github-actions github-actions bot closed this Nov 6, 2022
@majkrzak
Copy link
Contributor

What is the status of this? If I understand correctly something is wrong with the way this code is written, but I don't see any commend explaining what. If this works and somebody can review and explain what need to be fixed I guess I can give some effort to do it.

@Hedda
Copy link
Contributor

Hedda commented Nov 20, 2022

What is the status of this? If I understand correctly something is wrong with the way this code is written, but I don't see any commend explaining what. If this works and somebody can review and explain what need to be fixed I guess I can give some effort to do it.

@majkrzak Suggest that you maybe post that question for discussion here? -> #341 (see puddly posted there not so long ago)

Alternatively, perhaps consider resubmitting cleanup of patch as a new pull request to start a new review? -> #656 (comment)

fholzer added a commit to fholzer/zigpy that referenced this pull request Apr 22, 2023
@Hedda
Copy link
Contributor

Hedda commented Jun 5, 2023

Suggest that you maybe post that question for discussion here? -> #341 (see puddly posted there not so long ago)

FYI, based on PRs #1213 and zigpy/zha-device-handlers#2414 it looks like @nworbneb is now working on ZGP support for zigpy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet