Skip to content
Snippets Groups Projects
Commit ce903412 authored by jkerdreu's avatar jkerdreu
Browse files

Added support for RGB light & sound

git-svn-id: https://redmine.imt-atlantique.fr/svn/xaal/code/Python/trunk@2046 b32b6428-25c9-4566-ad07-03861ab6144f
parent d102f42a
No related branches found
No related tags found
No related merge requests found
......@@ -3,7 +3,13 @@ from xaal.lib import tools,Device
import ujson
import logging
from functools import partial
import socket
import binascii
from Crypto.Cipher import AES
GW_PORT = 9898
AQARA_ENCRYPT_IV = b'\x17\x99\x6d\x09\x3d\x28\xdd\xb3\xba\x69\x5a\x2e\x6f\x58\x56\x2e'
logger = logging.getLogger(__name__)
......@@ -34,39 +40,43 @@ class AqaraDev(object):
if not cmd:
logger.warning('pkt w/ no command: %s' % pkt)
return
if cmd in ['report','heartbeat']:
pload = pkt.get('data',None)
if pload:
data = ujson.decode(pload)
if cmd == 'report':
data = pkt.get('data',None)
if data:
pload = ujson.decode(data)
self.report(pload)
elif cmd=='heartbeat':
pass
self.on_report(data)
if cmd == 'heartbeat':
self.on_heartbeat(data)
else:
logger.info(pkt)
def report(self,data):
def on_report(self,data):
logger.info('Unhandled report %s' % data)
def on_heartbeat(self,data):
print(data)
class Switch(AqaraDev):
def setup(self):
dev = Device('button.basic',self.base_addr+'00')
self.devices.append(dev)
def report(self,data):
def on_report(self,data):
status = data.get('status',None)
if status:
self.devices[0].send_notification(status)
class Switch86(AqaraDev):
class Switch86sw2(AqaraDev):
def setup(self):
btn1 = Device('button.basic',self.base_addr+'00')
btn2 = Device('button.basic',self.base_addr+'01')
btn3 = Device('button.basic',self.base_addr+'02')
self.devices = self.devices + [btn1,btn2,btn3]
def report(self,data):
def on_report(self,data):
chans = ['channel_0','channel_1','dual_channel']
idx = 0
for k in chans:
......@@ -77,22 +87,13 @@ class Switch86(AqaraDev):
self.devices[idx].send_notification(r)
idx = idx + 1
class Gateway(AqaraDev):
def setup(self):
pass
def parse(self,pkt):
pass
class Weather(AqaraDev):
def setup(self):
self.devices.append(devices.thermometer(self.base_addr+'00'))
self.devices.append(devices.hygrometer(self.base_addr+'01'))
self.devices.append(devices.barometer(self.base_addr+'02'))
def report(self,data):
def on_report(self,data):
val = data.get('temperature',None)
if val: self.devices[0].attributes['temperature'] = round(int(val) / 100.0,1)
val = data.get('humidity',None)
......@@ -104,7 +105,7 @@ class Motion(AqaraDev):
def setup(self):
self.devices.append(devices.motion(self.base_addr+'00'))
def report(self,data):
def on_report(self,data):
val = data.get('status',None)
if val and val == 'motion':
self.devices[0].attributes['presence'] = True
......@@ -119,10 +120,123 @@ class Magnet(AqaraDev):
dev.unsupported_methods = ['open','close']
self.devices.append(dev)
def report(self,data):
def on_report(self,data):
status = data.get('status',None)
if status and status == 'open':
self.devices[0].attributes['position'] = True
if status and status == 'close':
self.devices[0].attributes['position'] = False
class Cube(AqaraDev):pass
class Gateway(AqaraDev):
def setup(self):
self.ip = None
self.token = None
self.rgb = None
self.connect()
lamp = devices.lamp(self.base_addr+'00')
lamp.methods['on'] = self.lamp_on
lamp.methods['off'] = self.lamp_off
lamp.methods['rand'] = self.lamp_rand
self.devices.append(lamp)
siren = Device('siren.sound',self.base_addr+'01')
siren.methods['play'] = self.siren_play
siren.methods['stop'] = self.siren_stop
self.devices.append(siren)
@property
def secret(self):
return self._secret
@secret.setter
def secret(self,value):
logger.debug('Seting GW secret to %s' % value)
self._secret = value
def make_key(self):
cipher = AES.new(self.secret, AES.MODE_CBC, IV=AQARA_ENCRYPT_IV)
return binascii.hexlify(cipher.encrypt(self.token)).decode("utf-8")
def connect(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.settimeout(0.5)
def send(self,pkt):
if not self.ip:
logger.warning("GW not found, please wait")
return
try:
print(pkt)
self.sock.sendto(pkt,(self.ip,GW_PORT))
ans = self.sock.recv(65507)
return ans
except Exception as e:
print(e)
def write(self,data = {}):
key = self.make_key()
data.update({"key":key})
pload = {"cmd":"write",
"sid": self.sid,
"data" : data
}
pkt = ujson.encode(pload).encode('utf8')
return self.send(pkt)
## RGB Leds
def get_rgb(self,red,green,blue,brightness=0xFF):
return brightness<<24|( red << 16)|( green << 8)|blue
def lamp_set(self,value):
data = {"rgb" : value}
print(self.write(data))
def lamp_on(self):
color = self.rgb or self.get_rgb(255,170,170)
self.lamp_set(color)
def lamp_off(self):
self.lamp_set(0)
def lamp_rand(self):
import random
red = random.randint(0,255)
green = random.randint(0,255)
blue = random.randint(0,255)
rgb = self.get_rgb(red,green,blue)
self.lamp_set(rgb)
## Siren go here
def siren_play(self,_sound=26,_volume=5):
data = {
"mid" : _sound,
"volume": _volume,
}
self.write(data)
def siren_stop(self):
data = { "mid" : 999 }
print(self.write(data))
def parse(self,pkt):
# the Gateway need to parse the token addtionnal parameter
cmd = pkt.get('cmd',None)
if cmd == 'heartbeat':
token = pkt.get('token',None)
if token: self.token = token
AqaraDev.parse(self,pkt)
def on_heartbeat(self,data):
ip = data.get('ip',None)
if ip and ip != self.ip:
self.ip = ip
def on_report(self,data):
rgb = data.get('rgb',None)
if rgb:
rgb = int(rgb)
if rgb != 0:
self.rgb = rgb
\ No newline at end of file
......@@ -13,10 +13,10 @@ logger = tools.get_logger(PACKAGE_NAME,'DEBUG')
def find_device_class(model):
if model in ['sensor_switch.aq3','sensor_switch.aq2','switch',]:
if model in ['sensor_switch.aq3','sensor_switch.aq2','switch','86sw1']:
return devices.Switch
if model == '86sw2':
return devices.Switch86
return devices.Switch86sw2
if model == 'gateway':
return devices.Gateway
if model == 'weather.v1':
......@@ -25,6 +25,8 @@ def find_device_class(model):
return devices.Motion
if model in ['magnet','sensor_magnet.aq2']:
return devices.Magnet
if model == 'sensor_cube.aqgl01':
return devices.Cube
return None
class GW(gevent.Greenlet):
......@@ -49,13 +51,16 @@ class GW(gevent.Greenlet):
self.aqara = AqaraConnector()
devs = self.cfg['devices']
for sid in devs:
model = devs[sid].get('model',None)
base_addr = devs[sid].get('base_addr',None)
cfg = devs[sid]
model = cfg.get('model',None)
base_addr = cfg.get('base_addr',None)
# TBD : Merge this w/ handle new device
if model and base_addr:
klass = find_device_class(model)
if klass:
dev = klass(sid,model,base_addr)
if model == 'gateway':
dev.secret = devs[sid].get('secret',None)
self.engine.add_devices(dev.devices)
self.devices.update({sid:dev})
......@@ -88,6 +93,8 @@ class GW(gevent.Greenlet):
dev.parse(pkt)
def _exit(self):
cfg = tools.load_cfg(PACKAGE_NAME)
if cfg != self.cfg:
logger.info('Saving configuration file')
self.cfg.write()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment