Skip to content

Commit

Permalink
Merge pull request #94 from doudz/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
doudz committed Feb 10, 2019
2 parents 35568e7 + afb2965 commit 8fadc64
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 16 deletions.
2 changes: 2 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,8 @@ def test_attribute_discovery(self):
'name': 'colour_mode', 'value': None}])

def test_reporting_request(self):
device = core.Device()
self.zigate._devices['1234'] = device
self.zigate.reporting_request('1234', 3, 0x0300, (0x0000, 0x20))
self.assertEqual(hexlify(self.zigate.connection.get_last_cmd()),
b'0212340103030000000000010020000000010e10000000'
Expand Down
12 changes: 12 additions & 0 deletions tests/test_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@ def test_reponse_8102_vibration(self):
('rssi', 255)])
)

def test_response_8009(self):
msg_data = unhexlify(b'00000123456789abcdef12340123456789abcdef0b')
r = responses.R8009(msg_data, 255)
self.assertDictEqual(r.data,
OrderedDict([('addr', '0000'),
('ieee', '0123456789abcdef'),
('panid', 4660),
('extended_panid', 81985529216486895),
('channel', 11),
('rssi', 255)])
)


if __name__ == '__main__':
unittest.main()
47 changes: 36 additions & 11 deletions zigate/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ def __init__(self, port='auto', path='~/.zigate.json',

self._addr = None
self._ieee = None
self.panid = 0
self.extended_panid = 0
self.channel = 0
self._started = False
self._no_response_count = 0

Expand Down Expand Up @@ -332,11 +335,14 @@ def autoStart(self, channel=None):
LOGGER.debug('Network is down, start it')
self.start_network(True)

if version['version'] >= '3.0f':
if version and version['version'] >= '3.0f':
LOGGER.debug('Set Zigate Time (firmware >= 3.0f)')
self.set_time()
self.get_devices_list(True)
self.need_discovery()
t = threading.Thread(target=self.need_discovery)
t.setDaemon(True)
t.start()
# self.need_discovery()

def need_discovery(self):
'''
Expand Down Expand Up @@ -736,7 +742,11 @@ def get_version(self, refresh=False):
get zigate firmware version
'''
if not self._version or refresh:
self._version = self.send_data(0x0010, wait_response=0x8010).data
r = self.send_data(0x0010, wait_response=0x8010)
if r:
self._version = r.data
else:
LOGGER.warning('Failed to retrieve zigate firmware version')
return self._version

def get_version_text(self, refresh=False):
Expand Down Expand Up @@ -810,9 +820,9 @@ def stop_permit_join(self):
'''
return self.permit_join(0)

def set_expended_panid(self, panid):
def set_extended_panid(self, panid):
'''
Set Expended PANID
Set Extended PANID
'''
data = struct.pack('!Q', panid)
return self.send_data(0x0020, data)
Expand Down Expand Up @@ -842,6 +852,9 @@ def get_network_state(self):
data = r.cleaned_data()
self._addr = data['addr']
self._ieee = data['ieee']
self.panid = data['panid']
self.extended_panid = data['extended_panid']
self.channel = data['channel']
return data

def start_network(self, wait=False):
Expand Down Expand Up @@ -1332,11 +1345,12 @@ def identify_trigger_effect(self, addr, endpoint, effect="blink"):
'finish_effect': 0xfe,
'stop_effect': 0xff
}
addr_mode = self._choose_addr_mode(addr)
addr = self.__addr(addr)
if effect not in effects.keys():
effect = 'blink'
effect_variant = 0 # Current Zigbee standard doesn't provide any variant
data = struct.pack('!BHBBBB', 2, addr, 1, endpoint, effects[effect], effect_variant)
data = struct.pack('!BHBBBB', addr_mode, addr, 1, endpoint, effects[effect], effect_variant)
return self.send_data(0x00E0, data)

def read_attribute_request(self, addr, endpoint, cluster, attribute,
Expand All @@ -1345,17 +1359,19 @@ def read_attribute_request(self, addr, endpoint, cluster, attribute,
Read Attribute request
attribute can be a unique int or a list of int
'''
addr_mode = self._choose_addr_mode(addr)
addr = self.__addr(addr)
if not isinstance(attribute, list):
attribute = [attribute]
length = len(attribute)
manufacturer_specific = manufacturer_code != 0
for i in range(0, length, 10):
sub_attribute = attribute[i: i + 10]
data = struct.pack('!BHBBHBBHB{}H'.format(length), 2, addr, 1,
sub_length = len(sub_attribute)
data = struct.pack('!BHBBHBBHB{}H'.format(sub_length), addr_mode, addr, 1,
endpoint, cluster,
direction, manufacturer_specific,
manufacturer_code, length, *sub_attribute)
manufacturer_code, sub_length, *sub_attribute)
self.send_data(0x0100, data)

def write_attribute_request(self, addr, endpoint, cluster, attributes,
Expand All @@ -1365,6 +1381,7 @@ def write_attribute_request(self, addr, endpoint, cluster, attributes,
attribute could be a tuple of (attribute_id, attribute_type, data)
or a list of tuple (attribute_id, attribute_type, data)
'''
addr_mode = self._choose_addr_mode(addr)
addr = self.__addr(addr)
fmt = ''
if not isinstance(attributes, list):
Expand All @@ -1376,7 +1393,7 @@ def write_attribute_request(self, addr, endpoint, cluster, attributes,
attributes_data += attribute_tuple
length = len(attributes)
manufacturer_specific = manufacturer_code != 0
data = struct.pack('!BHBBHBBHB{}'.format(fmt), 2, addr, 1,
data = struct.pack('!BHBBHBBHB{}'.format(fmt), addr_mode, addr, 1,
endpoint, cluster,
direction, manufacturer_specific,
manufacturer_code, length, *attributes_data)
Expand All @@ -1389,6 +1406,7 @@ def reporting_request(self, addr, endpoint, cluster, attributes,
attribute could be a tuple of (attribute_id, attribute_type)
or a list of tuple (attribute_id, attribute_type)
'''
addr_mode = self._choose_addr_mode(addr)
addr = self.__addr(addr)
if not isinstance(attributes, list):
attributes = [attributes]
Expand All @@ -1410,7 +1428,7 @@ def reporting_request(self, addr, endpoint, cluster, attributes,
change
]
manufacturer_specific = manufacturer_code != 0
data = struct.pack('!BHBBHBBHB{}'.format(fmt), 2, addr, 1, endpoint, cluster,
data = struct.pack('!BHBBHBBHB{}'.format(fmt), addr_mode, addr, 1, endpoint, cluster,
direction, manufacturer_specific,
manufacturer_code, length, *attributes_data)
r = self.send_data(0x0120, data, 0x8120)
Expand Down Expand Up @@ -1934,14 +1952,19 @@ class FakeZiGate(ZiGate):
Fake ZiGate for test only without real hardware
'''
def __init__(self, port='auto', path='~/.zigate.json',
auto_start=True, auto_save=True, channel=None, adminpanel=False):
auto_start=False, auto_save=False, channel=None, adminpanel=False):
ZiGate.__init__(self, port=port, path=path, auto_start=auto_start, auto_save=auto_save,
channel=channel, adminpanel=adminpanel)
self._addr = '0000'
self._ieee = '0123456789abcdef'
# by default add a fake xiaomi temp sensor on address abcd
device = Device({'addr': 'abcd', 'ieee': '0123456789abcdef'}, self)
device.set_attribute(1, 0, {'attribute': 5, 'rssi': 170, 'data': 'lumi.weather'})
device.load_template()
self._devices['abcd'] = device

def autoStart(self, channel=None):
ZiGate.autoStart(self, channel=channel)
self.connection.start_fake_response()

def setup_connection(self):
Expand Down Expand Up @@ -2086,6 +2109,8 @@ def _bind_report(self, enpoint_id=None):
self._zigate.bind_addr(self.addr, endpoint_id, 0x0001)
self._zigate.reporting_request(self.addr, endpoint_id,
0x0001, (0x0020, 0x20))
self._zigate.reporting_request(self.addr, endpoint_id,
0x0001, (0x0021, 0x20))
if 0x0006 in endpoint['in_clusters']:
LOGGER.debug('bind and report for cluster 0x0006')
self._zigate.bind_addr(self.addr, endpoint_id, 0x0006)
Expand Down
4 changes: 2 additions & 2 deletions zigate/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,8 @@ class R8009(Response):
type = 'Network state response'
s = OrderedDict([('addr', 'H'),
('ieee', 'Q'),
('pan', 'H'),
('extend_pan', 'Q'),
('panid', 'H'),
('extended_panid', 'Q'),
('channel', 'B'),
])

Expand Down
4 changes: 2 additions & 2 deletions zigate/templates/lumi.sensor_cube.aqgl01.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@
"cluster": 12
}
],
"device": 0,
"device": 24323,
"endpoint": 3,
"in_clusters": [],
"out_clusters": [],
"profile": 0
"profile": 260
}
],
"generictype": "sensor",
Expand Down
96 changes: 96 additions & 0 deletions zigate/templates/lumi.sensor_cube.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"endpoints": [
{
"clusters": [
{
"attributes": [
{
"attribute": 4,
"data": "LUMI"
},
{
"attribute": 5,
"data": "lumi.sensor_cube"
},
{
"attribute": 7,
"data": 3
}
],
"cluster": 0
}
],
"device": 24321,
"endpoint": 1,
"in_clusters": [
0,
3,
25,
18
],
"out_clusters": [
0,
4,
3,
5,
25,
18
],
"profile": 260
},
{
"clusters": [
{
"attributes": [
{
"attribute": 85
}
],
"cluster": 18
}
],
"device": 24322,
"endpoint": 2,
"in_clusters": [
3,
18
],
"out_clusters": [
4,
3,
5,
18
],
"profile": 260
},
{
"clusters": [
{
"attributes": [
{
"attribute": 65285
},
{
"attribute": 85
}
],
"cluster": 12
}
],
"device": 24323,
"endpoint": 3,
"in_clusters": [],
"out_clusters": [],
"profile": 260
}
],
"generictype": "sensor",
"info": {
"bit_field": "0100000000000010",
"descriptor_capability": "00000000",
"mac_capability": "10000000",
"manufacturer_code": "1037",
"power_type": 0,
"server_mask": 0
}
}
1 change: 1 addition & 0 deletions zigate/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def __init__(self):
self.sent = []
self.auto_responder = {}
self.add_auto_response(0x0010, 0x8010, unhexlify(b'000f3ff0'))
self.add_auto_response(0x0009, 0x8009, unhexlify(b'00000123456789abcdef12340123456789abcdef0b'))
# by default add a fake xiaomi temp sensor on address abcd
self.add_auto_response(0x0015, 0x8015, unhexlify(b'01abcd0123456789abcdef00aa'))

Expand Down
2 changes: 1 addition & 1 deletion zigate/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
# file that was distributed with this source code.
#

__version__ = '0.27.3'
__version__ = '0.27.5'

0 comments on commit 8fadc64

Please sign in to comment.