Using xAP and Python
In this section we discuss how to interface with xAP devices, with a bias to the Home Automation Hub, using the Python programming language. Even with very minimal skills you can modify and change the sample programs provided to create your own solutions.
As Python run on Windows as well as Linux these programs will work on both platforms. As well as natively on the livebox if you grab the Python for MIPS bundle.
Simplistic samples
Remember as xAP is a Broadcast protocol none of these programs need to be executed on the Livebox to interact with its hardware. As these programs are demonstrators none of them are xAP-hub aware so only one can be ran on a computer at a time. They demonstrate the absolute minimum amount of code that is necessary to send and receive xAP messages.
xAP message snooper
Listening to xAP messages on the LAN
#!/usr/bin/env python # xAP message listener - simplistic import socket, traceback host = '' s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind((host, 3639)) while 1: try: message, address = s.recvfrom(8192) print "%s: %s" % (address, message) except (KeyboardInterrupt, SystemError): raise except: traceback.print_exc()
xAP relay toggle
Toggling the relays on and off using python is very easy. Each will go TICK on/off in sequence.
import socket import time s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) for relay in range(1,5): for state in ['on','off']: msg="""xap-header { v=12 hop=1 uid=FF000F00 class=xAPBSC.cmd source=dbzoo.livebox.demo target=dbzoo.livebox.controller:relay.%s } output.state.1 { id=* state=%s } """ s.sendto(msg % (relay, state), ('<broadcast>', 3639)) time.sleep(1)
xAP LCD Clock
A simplistic xAP CLOCK in python. Every minute the LCD of the livebox will be updated.
#!/usr/bin/env python # xAP - Simplistic LCD Clock from socket import * from time import localtime, strftime, sleep s = socket(AF_INET, SOCK_DGRAM) s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) while 1: msg="""xap-header { v=12 hop=1 uid=FF000F00 class=xAPBSC.cmd source=dbzoo.livebox.demo target=dbzoo.livebox.Controller:lcd } output.state.1 { id=* text=%s } """ t = localtime() s.sendto(msg % strftime("%d %b, %H:%M", t), ('<broadcast>', 3639)) sleep(60 - t[5])
Need an xAP HUB
Without a HUB we are only able to run a single xAP program on a computer at a time, as port 3639, the default xAP port, can only be accessed by one program.
To get around this limitation we run an xAP hub, this performs the same function a the hardware variant of the same name. It allows multiple xAP applications to share the 3639 port which the HUB will manage for us.
The portable distribution comes with a tiny memory footprint high speed xap-hub
xAP support Library
The support library xaplib.zip provides additional code to handle integration with a HUB.
#!/usr/bin/env python # # XAP support library import socket, traceback, time class Xap: def __init__(self, uid, source): self.heartbeat_tick = 0; self.uid = uid self.source = source self.port = 0 self.running = 1 def run(self, func): self.connect() while self.running: if self.port: self.heartbeat(60) try: func(self) except KeyboardInterrupt: self.done() pass except socket.timeout: pass except: traceback.print_exc() self.done() def done(self): self.gout.close() self.gin.close() self.running = 0 def connect(self): host = '' self.gin = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.gin.settimeout(60) try: self.gin.bind((host, 3639)) except socket.error, msg: print "Broadcast socket port 3639 in use" print "Assuming a hub is active" host = '127.0.0.1' for self.port in range(3639,4639): try: self.gin.bind((host, self.port)) except socket.error, msg: print "Socket port %s in use" % self.port continue print "Discovered port %s" % self.port break self.gout = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.gout.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) def send(self ,msg): self.gout.sendto(msg, ('<broadcast>', 3639)) def sendMsg(self, clazz, target, msg): msg = """xap-header { v=12 hop=1 uid=%s class=%s source=%s target=%s } %s""" % (self.uid, clazz, self.source, target, msg) self.send(msg) def sendLCDMsg(self, msg): msg = "output.state.1\n{\nid=*\ntext=%s\n}" % msg self.sendMsg("xAPBSC.cmd","dbzoo.livebox.Controller:lcd", msg) def sendSMS(self, num, msg): msg = "outbound\n{\nnum=%s\nmsg=%s\n}" % (num, msg) self.sendMsg("sms.message","dbzoo.livebox.sms", msg) def receive(self): try: return self.gin.recvfrom(8192) except KeyboardInterrupt: self.done() pass # The HUB won't relay messages to us until it see's our heartbeat knows our listening port. # This must be periodically sent to keep it active on the HUB. def heartbeat(self, interval): now = time.time() if now - self.heartbeat_tick > interval or self.heartbeat_tick == 0: self.heartbeat_tick = now msg="""xap-hbeat { nv=12 hop=1 uid=%s class=xap-hbeat-alive source=%s interval=%s port=%s }""" self.send(msg % (self.uid, self.source, interval, self.port))
HUB aware samples
The support library greatly simplifies the process of writing a small xaplet.
xAP message snoop
A message snooper is now trivially implemented
#!/usr/bin/env python # xAP message listener - HUB aware from xaplib import Xap def snoopTraffic(xap): print "MSG: %s ADDR: %s" % xap.receive() Xap("FF000F00","dbzoo.livebox.Snoop").run(snoopTraffic)
xAP LCD Clock
Revisiting our simplistic clock we can rewrite the code using fewer lines and at the same time making it hub friendly.
#!/usr/bin/env python # LCD Clock from xaplib import Xap from time import localtime, strftime, sleep def clock(xap): t = localtime() xap.sendLCDMsg( strftime("%d %b, %H:%M", t) ) sleep(60 - t[5]) Xap("FF000F00","dbzoo.livebox.demo").run(clock)
Demo code
Some other samples which might be useful
- xap-sms-event.zip - Watch out for an RF or RELAY event when one if detected send an SMS of the change
- xap-sms-lcd.zip - Watch out for inbound SMS messages when one if detected display the message on the livebox LCD
- xap-input-smtp.zip - Send an email on an input event