Here is a starting point for the python code. It works pretty well. You need to set the com port for your gateway near the beginning of the code.
I don't have time to try to explain everything about it, but feel free to ask questions. Ideally this code should be written to put everything into a class but I'm not that experienced with python, and although I would be able to do it it would take me more time than I want to spend on it at the moment. If anyone out there who is good with python wants to help that would be great.
#VoxCommando read/write to serial port by James&Kalle
#you must have enabled the python-plugin in VoxCommando
#start this python script with VoxCommando
#this code is for using Sensors which build with sketches and Sensors from www.MySensors.org
#Protocol
#http://www.mysensors.org/build/serial_api
import clr
import io,json,sys
import time
clr.AddReference('System')
from System import *
from System.Collections.Generic import *
import traceback
## Init variables...
useComPort="COM3"
global sValSum
sValSum = ""
global inclusionMode
inclusionMode = True
minID=1 # default: 1
maxID=255 # defualt: 255
## prepare / clear log file
logFile = open("PY\\sensorLog.txt", "wt")
logFile.close()
## Initialize, try to load known IDs from file
## If a sensor is no longer used you can edit the text file "PY\sensorIDs.txt" to remove the id so it can be assigned to a new sensor.
try:
readIDsFile = open("PY\\sensorIDs.txt", "rt")
txtIDs = readIDsFile.read()
readIDsFile.close()
sensorIDs = json.loads(txtIDs)
print "loaded IDs"
print sensorIDs
except:
print "unable to load sensor IDs"
sensorIDs = []
def log(txt):
with open("PY\\sensorLog.txt", "a") as myfile:
myfile.write(txt+'\n')
def saveIDsToFile(saveIDs):
saveIDs.sort()
IDsFile = open("PY\\sensorIDs.txt", "wt")
strData = json.dumps(saveIDs)
IDsFile.write(strData)
IDsFile.close()
def registerID(newID):
intID = int(newID)
global sensorIDs
if intID in sensorIDs:
log( "ID already registered: "+str(newID))
else:
log( "registering new ID: "+newID)
sensorIDs.append(intID)
saveIDsToFile(sensorIDs)
def getNewID():
global sensorIDs
for i in range(minID,maxID):
if not (i in sensorIDs):
return i
return -1
def assignFreeID():
global inclusionMode
# we can check here to see if we are in "including mode or not"
# and if not then just log and return without assigning an ID
newID = getNewID();
log("free node ID: "+str(newID))
if newID==-1:
log( "error: there are no free IDs left!")
else:
if inclusionMode:
strMessage = "255;255;3;0;4;"+str(newID)
serialPort.WriteLine(strMessage)
print strMessage
log( "assigned new ID to sensor: " + strMessage)
else:
log("not in inclusionMode so not assigning ID to node")
###
### END of new sensor ID section
###
sensorTypes = {"0":"TEMP", "1":"HUM", "2":"LIGHT", "3":"DIMMER", "4":"PRESSURE", "5":"FORECAST", "6":"RAIN", "7":"RAINRATE", "8":"WIND", "9":"GUST", "10":"DIRECTION", "11":"UV", "12":"WEIGHT", "13":"DISTANCE", "14":"IMPEDANCE", "15":"ARMED", "16":"MOTION", "17":"WATT", "18":"KWH", "19":"SCENE_ON", "20":"SCENE_OFF", "21":"HEATER", "22":"HEATER_SW", "23":"LIGHT_LEVEL", "24":"VAR1", "25":"VAR2", "26":"VAR3", "27":"VAR4", "28":"VAR5", "29":"UP", "30":"DOWN", "31":"STOP", "32":"IR_SEND", "33":"IR_RECEIVE", "34":"FLOW", "35":"VOLUME", "36":"LOCK_STATUS", "37":"DUST_LEVEL", "38":"VOLTAGE", "39":"CURRENT"}
IntsubTypes = {"0":"BATTERY", "1":"TIME", "2":"VERSION", "3":"ID-REQUEST", "4":"ID-RESPONSE", "5":"INCLUSIONMODE", "6":"CONFIG", "7":"FIND-PARENT", "8":"RESPONSE-PARENT", "9":"LOG-MESSAGE", "10":"CHILDREN", "11":"SKETCHNAME", "12":"SKETCHVERSION", "13":"REBOOT", "14":"GATEWAY-READY"}
presTypes = {"0":"DOOR", "1":"MOTION", "2":"SMOKE", "3":"LIGHT", "4":"DIMMER", "5":"COVER", "6":"TEMP", "7":"HUM", "8":"BARO", "9":"WIND", "10":"RAIN", "11":"UV", "12":"WEIGHT", "13":"POWER", "14":"HEATER", "15":"DISTANCE", "16":"LIGHTLEVEL", "17":"ARDUINONODE", "18":"ARDUINORELAY", "19":"LOCK", "20":"IR", "21":"WATER", "22":"AIRQUALITY", "23":"CUSTOM", "24":"DUST", "25":"SCENECONTROLLER"}
def Ondata (sender, event):
try:
processData (sender)
except:
log( "error receiving serial data...")
log( traceback.format_exc() )
def processData (sender):
global sValSum
sData = sender.ReadLine ()
log("========NEW MESSAGE======")
log(sData )
dataParts = sData.split(";")
sensorID = dataParts[0]
childID = dataParts[1]
friendlyID = sensorID+"|"+childID
msgType = dataParts[2]
msgPayload = dataParts[5]
log( "Message type: "+msgType )
if msgType=="1":
#SET VALUE Message
sVal = msgPayload
if sVal[-1] == "+":
sValSum = sValSum + sVal[0:len(sVal)-1]
else:
print "SET VALUE Message -- node: " +friendlyID
registerID(sensorID)
sensTypeNum=dataParts[4]
sensorType = sensorTypes[sensTypeNum]
sValSum = sValSum + msgPayload
vc.triggerEvent("MySensorsValue."+sensorType+"."+friendlyID+"."+sValSum, List[str]([dataParts[0],dataParts[1],sValSum, sensorType]))
sValSum = ""
elif msgType=="0":
#PRESENTATION Message
log( "PRESENTATION Message")
#registerID(sensorID)
presTypeNum=dataParts[4]
presType = presTypes[presTypeNum]
log( "presType: "+presTypeNum+": "+presType)
#vc.triggerEvent("MySensorsPres."+presType+"."+friendlyID+"."+msgPayload, List[str]([dataParts[0],dataParts[1],msgPayload, presType]))
elif msgType=="3":
#INTERNAL Message
#log( "INTERNAL Message" )
IntsubTypeNum=dataParts[4]
IntsubType = IntsubTypes[IntsubTypeNum]
log( "Internal Message subType: "+IntsubTypeNum+": "+IntsubType )
#vc.triggerEvent("MySensorsIntsub."+IntsubType+"."+friendlyID+"."+msgPayload, List[str]([dataParts[0],dataParts[1],msgPayload, IntsubType]))
if sData=="255;255;3;0;3;" :
log( "Sensor has requested a new ID" )
assignFreeID()
def arduinoWrite(sendMessage):
global logbool
strParts = sendMessage.split(";")
length = len(strParts[5])
strPartsMsg = strParts[5]
print "sending: "+sendMessage
chunkSize=22
if length > chunkSize:
msgHeader=strParts[0]+";"+strParts[1]+";"+strParts[2]+";"+strParts[3]+";"+strParts[4]+";"
end = int(round(length/chunkSize-0.5))
for i in range(0, end):
msgPart = strPartsMsg[(i*chunkSize):((i+1)*chunkSize)]
print "chunk: "+ msgPart
serialPort.WriteLine(msgHeader+msgPart+"+")
time.sleep(0.1)
msgPart = strPartsMsg[((end)*chunkSize):(length)]
print "final chunk: "+ msgPart
serialPort.WriteLine(msgHeader+msgPart)
else:
serialPort.WriteLine(sendMessage)
print str
serialPort = IO.Ports.SerialPort(useComPort) #Which serial port which your gateway device is connected to
serialPort.BaudRate = 115200 #Baudrate for mySensors (must be 115000)
serialPort.DataBits = 8
serialPort.DataReceived += Ondata #function to call when serial data arrives from the gateway device
serialPort.Open()
log( "Serial connection established" )
vc.triggerEvent("MySensors.GatewayReady",None)
You can get this code to load at startup with something like this command:
<?xml version="1.0" encoding="utf-16"?>
<!--VoxCommando 2.1.4.2-->
<command id="1196" name="load python" enabled="true" alwaysOn="False" confirm="False" requiredConfidence="0" loop="False" loopDelay="0" loopMax="0" description="">
<action>
<cmdType>PY.ExecFile</cmdType>
<params>
<param>PY\MySensors20150303.py</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<event>python ready</event>
</command>