Skip to content

Commit c092964

Browse files
Version 0.1.0 Don't create an object for every discovered device.
1 parent 4ee70d6 commit c092964

19 files changed

+1466
-924
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,6 @@ ENV/
9090

9191
# Mac Project Files
9292
.DS_Store
93+
94+
# Intellij
95+
.idea/

.travis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
language: python
22
python:
33
- "2.7"
4-
- "3.4"
5-
- "3.5"
64
# command to run tests
75
script: nosetests

classes/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from classes.constants import Constants
21
from classes.base import Base
2+
from classes.hub import Hub
33
from classes.device import Device
44
from classes.smartplug import SmartPlug
5-
from classes.sensor import Sensor
6-
from classes.loginit import *
5+
from classes.sensor import Sensor

classes/base.py

Lines changed: 237 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,244 @@
1+
import pprint
2+
import logging
3+
from classes import *
4+
import struct
5+
import time
16
import binascii
7+
import threading
8+
from xbee import ZigBee
9+
10+
pp = pprint.PrettyPrinter(indent=4)
11+
logger = logging.getLogger('pihive')
12+
13+
class Base(object):
14+
# ZigBee Profile IDs
15+
ZDP_PROFILE_ID = b'\x00\x00' # Zigbee Device Profile
16+
HA_PROFILE_ID = b'\x01\x04' # HA Device Profile
17+
ALERTME_PROFILE_ID = b'\xc2\x16' # AlertMe Private Profile
18+
19+
# ZigBee Addressing
20+
BROADCAST_LONG = b'\x00\x00\x00\x00\x00\x00\xff\xff'
21+
BROADCAST_SHORT = b'\xff\xfe'
22+
23+
messages = {
24+
'routing_table_request': {
25+
'description' : 'Management Rtg (Routing Table) Request',
26+
'src_endpoint' : b'\x00',
27+
'dest_endpoint' : b'\x00',
28+
'cluster' : b'\x00\x32',
29+
'profile' : ZDP_PROFILE_ID,
30+
'data' : '\x01'
31+
},
32+
'permit_join_request': {
33+
'description' : 'Management Permit Join Request',
34+
'src_endpoint' : b'\x00',
35+
'dest_endpoint' : b'\x00',
36+
'cluster' : b'\x00\x36',
37+
'profile' : ZDP_PROFILE_ID,
38+
'data' : '\xff\x00'
39+
},
40+
'match_descriptor_response': {
41+
'description' : 'Match Descriptor Response',
42+
'src_endpoint' : b'\x00',
43+
'dest_endpoint' : b'\x00',
44+
'cluster' : b'\x80\x06',
45+
'profile' : ZDP_PROFILE_ID,
46+
'data' : b'\x00\x00\x00\x00\x01\x02'
47+
#'data' : '\x03\xfd\xff\x16\xc2\x00\x01\xf0\x00' // SmartPlug
48+
},
49+
'active_endpoints_request': {
50+
'description' : 'Active Endpoints Request', #Device
51+
'src_endpoint' : b'\x00',
52+
'dest_endpoint' : b'\x00',
53+
'cluster' : b'\x00\x05',
54+
'profile' : ZDP_PROFILE_ID,
55+
'data' : b'\x00\x00'
56+
},
57+
58+
59+
60+
61+
'hardware_join_1' : {
62+
'description' : 'Hardware Join Messages 1', #Device
63+
'src_endpoint' : b'\x00',
64+
'dest_endpoint' : b'\x02',
65+
'cluster' : b'\x00\xf6',
66+
'profile' : ALERTME_PROFILE_ID,
67+
'data' : b'\x11\x01\xfc'
68+
},
69+
'hardware_join_2' : {
70+
'description' : 'Hardware Join Messages 2', #Device (also not Version req)
71+
'src_endpoint' : b'\x00',
72+
'dest_endpoint' : b'\x02',
73+
'cluster' : b'\x00\xf0',
74+
'profile' : ALERTME_PROFILE_ID,
75+
'data' : b'\x19\x01\xfa\x00\x01'
76+
},
77+
'version_info' : {
78+
'description' : 'Version Request', #Device
79+
'src_endpoint' : b'\x00',
80+
'dest_endpoint' : b'\x02',
81+
'cluster' : b'\x00\xf6',
82+
'profile' : ALERTME_PROFILE_ID,
83+
'data' : b'\x11\x00\xfc\x00\x01'
84+
},
85+
'plug_off': {
86+
'description' : 'Switch Plug Off', #SmartPlug
87+
'src_endpoint' : b'\x00',
88+
'dest_endpoint' : b'\x02',
89+
'cluster' : b'\x00\xee',
90+
'profile' : ALERTME_PROFILE_ID,
91+
'data' : b'\x11\x00\x02\x00\x01'
92+
},
93+
'plug_on': {
94+
'description' : 'Switch Plug On', #SmartPlug
95+
'src_endpoint' : b'\x00',
96+
'dest_endpoint' : b'\x02',
97+
'cluster' : b'\x00\xee',
98+
'profile' : ALERTME_PROFILE_ID,
99+
'data' : b'\x11\x00\x02\x01\x01'
100+
},
101+
'switch_status': {
102+
'description' : 'Switch Status', #SmartPlug
103+
'src_endpoint' : b'\x00',
104+
'dest_endpoint' : b'\x02',
105+
'cluster' : b'\x00\xee',
106+
'profile' : ALERTME_PROFILE_ID,
107+
'data' : b'\x11\x00\x01\x01'
108+
},
109+
'normal_mode': {
110+
'description' : 'Normal Mode', #SmartPlug
111+
'src_endpoint' : b'\x00',
112+
'dest_endpoint' : b'\x02',
113+
'cluster' : b'\x00\xf0',
114+
'profile' : ALERTME_PROFILE_ID,
115+
'data' : b'\x11\x00\xfa\x00\x01'
116+
},
117+
'range_test': {
118+
'description' : 'Range Test', # Device
119+
'src_endpoint' : b'\x00',
120+
'dest_endpoint' : b'\x02',
121+
'cluster' : b'\x00\xf0',
122+
'profile' : ALERTME_PROFILE_ID,
123+
'data' : b'\x11\x00\xfa\x01\x01'
124+
},
125+
'locked_mode': {
126+
'description' : 'Locked Mode', #SmartPlug
127+
'src_endpoint' : b'\x00',
128+
'dest_endpoint' : b'\x02',
129+
'cluster' : b'\x00\xf0',
130+
'profile' : ALERTME_PROFILE_ID,
131+
'data' : b'\x11\x00\xfa\x02\x01'
132+
},
133+
'silent_mode': {
134+
'description' : 'Silent Mode', #SmartPlug
135+
'src_endpoint' : b'\x00',
136+
'dest_endpoint' : b'\x02',
137+
'cluster' : b'\x00\xf0',
138+
'profile' : ALERTME_PROFILE_ID,
139+
'data' : b'\x11\x00\xfa\x03\x01'
140+
},
141+
'security_initialization': {
142+
'description' : 'Security Initialization', #Sensor
143+
'src_endpoint' : b'\x00',
144+
'dest_endpoint' : b'\x02',
145+
'cluster' : b'\x05\x00',
146+
'profile' : ALERTME_PROFILE_ID,
147+
'data' : b'\x11\x80\x00\x00\x05'
148+
}
149+
}
150+
151+
def __init__(self, serialObj):
152+
self.logger = logger or logging.getLogger(__name__)
153+
154+
# Setup serial and xbee
155+
self.zb = ZigBee(ser=serialObj, callback=self.receive_message, error_callback=self.xbee_error)
156+
157+
# Type Info
158+
self.manu = None
159+
self.type = None
160+
self.date = None
161+
self.version = None
162+
163+
# Received and Sent Messages
164+
self.outgoing_messages = []
165+
self.incoming_messages = []
166+
167+
self.associated = False
168+
169+
def halt(self):
170+
self.zb.halt()
171+
172+
def start(self, func):
173+
if callable(func):
174+
self.logger.debug('Starting thread...')
175+
self._stop = threading.Event()
176+
self.thread = threading.Thread(target=func)
177+
self.thread.start()
178+
else:
179+
self.logger.critical('Non callable function passed to start()')
180+
181+
def stop(self):
182+
self.logger.debug('Stopping thread...')
183+
self._stop.set()
184+
185+
def xbee_error(self, error):
186+
self.logger.critical('XBee Error %s', error)
187+
188+
def list_actions(self):
189+
actions = {}
190+
for id, message in self.messages.items():
191+
actions[id] = message['description']
192+
return actions
193+
194+
def get_action(self, type):
195+
# Get the message from the dictionary
196+
return self.messages[type]
197+
198+
def send_message(self, message, dest_addr_long, dest_addr):
199+
# Tack on destination addresses
200+
message['dest_addr_long'] = dest_addr_long
201+
message['dest_addr'] = dest_addr
202+
device_id = Base.pretty_mac(dest_addr_long)
203+
204+
self.logger.debug('Device ID: %s sent message...%s', device_id, message)
205+
self.zb.send('tx_explicit', **message)
206+
207+
def receive_message(self, message):
208+
# Grab source address, work out device ID
209+
source_addr_long = message['source_addr_long']
210+
device_id = Base.pretty_mac(source_addr_long)
211+
212+
self.logger.debug('Device ID: %s received message...%s', device_id, message)
213+
self.process_message(message)
214+
215+
def process_message(self, message):
216+
# We are only interested in Zigbee Explicit packets.
217+
if (message['id'] == 'rx_explicit'):
218+
profile_id = message['profile']
219+
cluster_id = message['cluster']
220+
221+
if (profile_id == self.ZDP_PROFILE_ID):
222+
# Zigbee Device Profile ID
223+
self.logger.debug('Zigbee Device Profile Packet Receieved')
224+
225+
elif (profile_id == self.ALERTME_PROFILE_ID):
226+
# AlertMe Profile ID
227+
self.logger.debug('AlertMe Specific Profile Packet Received')
228+
229+
elif (profile_id == self.HA_PROFILE_ID):
230+
# HA Profile ID
231+
self.logger.debug('HA Profile Packet Received')
232+
233+
else:
234+
self.logger.error('Unrecognised Profile ID: %e', profile_id)
235+
236+
def __str__(self):
237+
return "Device Type: %s" % (self.type)
2238

3-
class Base:
4239

5240
@staticmethod
6-
def prettyMac(macString):
241+
def pretty_mac(macString):
7242
# TODO: This may be a little over complicated at the moment,
8243
# I was struggling to get this to work for both Python2 and Python3.
9244
# I am sure this could be simplified... but for now - this works!

classes/constants.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)