I had the chance, at an Intel IoT Hackathon taking place at Usine.io in Paris, beside an Intel Edison Arduino board and a bunch of Grove sensors/actuators, to also get the new Akene board from Snootlab.
Thanks to the Intel IoT guys, Nicolas from SigFox and all the staff of BeMyApp for this Hackaton…
Step 1: The project...I decided to build a small light sensor station, with the Intel Edison board, the Grove shield, the SigFox Akene Shield, and an I2C Grove TSL2561.
This station will upload, through the SigFox network about every 10 minutes, 3 different values (in lux) relating to that 10 minutes period: the arithmetic average light, the minimum and maximum light.
That will allow to know how the light fluctuate around its average value for this period of time, and therefore to get the big picture on how the sky could be cloudy (if some wind at least to push the clouds…).
I will use Python for that project.
Step 2: A friendly Development EnvironmentI assume that the Intel Edison environment is ready for Python, and a password is set on the Edison in order to open SSH sessions and also SFTP to upload the python code.
I am using OS X, and will use CoolTerm for communication, and the excellent TextWrangler as code editor and code uploader (SFTP).
Step 3: The Framework: sensor.py#!/usr/bin/env python import time import mraa # Sensor initialisation import pyupm_tsl2561 tsl2561Ready = True if (tsl2561Ready) : # Instantiate a digital light sensor TSL2561 on I2C print "initialisation TLS2561" lightSensor = pyupm_tsl2561.TSL2561() time.sleep (10) # Value numberSamples = 200 valueCount = 0 valueNow = 0 valueSum = 0 valueAvg = 0 valueMin = 32767 valueMax = 0 # Main loop while True : if (valueCount == numberSamples) : print print "after", numberSamples, "samples (values in lux):" print "valueAvg: %5d" % valueAvg, "- valueMin: %5d" % valueMin, "- valueMax: %5d" % valueMax valueCount = 0 if (valueCount == 0) : valueNow = 0 valueSum = 0 valueAvg = 0 valueMin = 32767 valueMax = 0 if (tsl2561Ready) : valueNow = lightSensor.getLux() if (valueNow >= 0) : valueCount = valueCount + 1 valueSum = valueSum + valueNow valueAvg = valueSum / valueCount if valueNow < valueMin : valueMin = valueNow if valueNow > valueMax : valueMax = valueNow now = time.ctime(int(time.time())) if (valueCount == 1) : print print "Light (values in lux):" print now,"(GMT)",": %5d" % valueNow,"- avg:%5d" % valueAvg,"- min:%5d" % valueMin,"- max:%5d" % valueMax,"-%4d sample(s)" % valueCount time.sleep(1)Step 4: What you get with sensor.py
> python sensor.py
The Akene board is an experimentation Arduino shield from SnootLab with the TD1208 SoC (System on Chip) on it. The TD1208 is a SigFox-certified radio transceiver combined with an ARM Cortex M3, which implements the telecommunication modem stack for sending values to the SigFox operated telecommunication network, and also includes I2C capabilities for IoT sensors, beside its serial modem link.
SIgFox services rely on a LPWA (Low-Power Wide-Area) network currently deployed in Western Europe, San Francisco, as well as other countries or cities. The SigFox protocol is designed for small messages and its technology is focusing on energy efficiency for devices clients and large area coverage for each infrastructure base station.
The SigFox network allows each device to send up to 140 messages per day (i.e. every 10mn), each of them up to 12 available bytes i.e. 6 short integer values (the timestamp and the unique device ID are also transmitted in addition).
More informations: http://makers.sigfox.com
The Akene shield can be used as a modem, so we will first connect it to the Edison that way:
• Ground to Ground (Black wire)
• 3.3v to 3.3v (Red wire)
• serial Rx (pin 0) of Edison to Tx of Akene (pin D4) - Blue wire
• serial Tx (pin 1) of Edison to Rx of Akene (pin D5) - White wire
We can consider the TD1208 as a modem.
The PySerial package has to installed.
python -m serial.tools.miniterm
We use miniterm (part of PySerial) - and specify the serial port: /dev/ttyMFD1 - to send direct commands, like:
• AT
which should reply OK (otherwise there is a problem),
• AT&V
which reply by the TD1208 identification,
• AT$SS01234567
which send the 01234567 message to the SigFox network (the maximum hexadecimal digits is 24, i.e. 12 bytes), and
• AT?
which return the list of commands available.
To exit miniterm, on OS X with a french keyboard: CTRL 6
This is a fast adaptation of a python command dedicated for another TD1208 board (RPISIGFOX from SNOC) and found on internet.
Just to mention that, for using serial with Intel Edison,
• it is prior necessary to initialise the port / pins which will be used, in our case /dev/ttyMFD1 (pins 0 and 1):
import libmraa
x=Uart(0)
• the port is automatically open when calling serial.Serial(......
You can use the command that way:
python sendsigfox.py 01234567
which will send the message 01234567 to the SigFox network
#!/usr/bin/python
# This script allow the control of the SNOOTLAB expansion board, and is adapted for Intel Edison.
# 3 lines of code were added (LINE ADDED)
# script has been modified from:
#
# This script is from the rpisigfox expansion board for Raspberry Pi.
#
# V1.0 allow only to send regular message on the SigFox Network.
# syntax is :
# sendsigfox MESSAGE
# where MESSAGE is a HEXA string encoded. Can be 2 to 24 characters representing 1 to 12 bytes.
# Example : sendsigfox 00AA55BF to send the 4 bytes 0x00 0xAA 0x55 0xBF
#
import time
import serial
import sys
from time import sleep
#LINE ADDED
import mraa
SOH = chr(0x01)
STX = chr(0x02)
EOT = chr(0x04)
ACK = chr(0x06)
NAK = chr(0x15)
CAN = chr(0x18)
CRC = chr(0x43)
def getc(size, timeout=1):
return ser.read(size)
def putc(data, timeout=1):
ser.write(data)
sleep(0.001) # give device time to prepare new buffer and start sending it
def WaitFor(ser, s, timeOut):
nbMax = 0
ser.timeout = timeOut
currentMsg = ''
while currentMsg.endswith(s) != True :
# should add a try catch here
c=ser.read()
if c != '' :
currentMsg += c
else :
print 'timeout waiting for ' + s
return False
nbMax = nbMax + 1
if nbMax > 150:
print 'Timeout expired'
return False
return True
print('Sending SigFox Message...')
#LINE ADDED: 0 ie '/dev/ttyMFD1'
uart = mraa.Uart(0)
modem = serial.Serial(
uart.getDevicePath(),
baudrate=9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
#LINE ADDED: closing serial before opening it, as otherwise the Edison serial seems to be already open by calling serial.Serial
modem.close()
modem.open()
modem.write('AT\r')
if (WaitFor(modem, 'OK', 3)):
print('SigFox Modem OK')
else:
print('SigFox Modem Error')
modem.close()
exit()
modem.write("AT$SS={0}\r".format(sys.argv[1]))
print('Sending ...')
if (WaitFor(modem, 'OK', 15)):
print('OK Message sent')
else:
print('Error Sending message')
modem.close()
exit()
modem.close()
>python sendsigfox.py 346723
No special difficulty there also, just to mention:
• Each data sent is a short integer of 2 bytes. the valueAvg, valueMin and valueMax are therefore 6 bytes, i.e. 12 hexadecimal chars string. As the setup from SigFox in the case I am using is done in order that data are resent to actoboard.com, and that actoboard.com currently accept data in LittleEndian byte order, each data is, prior to be sent, transformed accordingly...
• the Akene shield is fully plugged on top of the Grove shield, and in order to fit the wiring of the serial of Edison on pins 0 and 1 and the serial of Akene on pins D4 and D5, straps has been used (0 to D4: White strap) and (1 to D5: Yellow strap), see first picture... That mean a clean wiring but no possibility to use Pin 4 and 5 of the Edison...
#!/usr/bin/env python
import time
import mraa
import serial
# convert a string (n chars) into its hexadecimal string representation (n bytes - 2*n chars)
def string2hex(s) :
return str(s).encode("hex")
# convert a short integer (2 bytes) into its hexadecimal (2 bytes) representation with BigEndian/LittleEndian bytes order
def short2hex(i, bigEndian) :
if (bigEndian) :
return "%04X" % i
else :
return "%04X" % (((i << 8) & 0xFF00) | ((i >> 8) & 0x00FF))
def WaitFor(serial, msg, timeOut):
nbMax = 0
serial.timeout = timeOut
currentMsg = ''
while currentMsg.endswith(msg) != True :
c = serial.read()
if c != '' :
currentMsg += c
else :
print 'timeout waiting for ' + msg
return False
nbMax = nbMax + 1
if nbMax > 150:
print 'Timeout expired'
return False
return True
def sendsigfox(data):
print('Sending SigFox Message...')
# 0 i.e. pins 0 and 1 i.e. '/dev/ttyMFD1' for Intel Edison, allow usage of UART on port 0
uart = mraa.Uart(0)
# define sigfox and implicitely makes a sigfox.open()
sigfox = serial.Serial(
uart.getDevicePath(),
baudrate=9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
sigfox.write('AT\r')
if (WaitFor(sigfox, 'OK', 3)):
print('SigFox Modem OK')
else:
print('SigFox Modem Error')
sigfox.close()
return False
print("sending data " + data + " to SigFox network:")
print("Sigfox: AT$SS=" + data + "\r")
sigfox.write("AT$SS=")
sigfox.write(data)
sigfox.write("\r")
if (WaitFor(sigfox, 'OK', 15)):
print('Message sent OK')
else:
print('Error Sending message')
sigfox.close()
return False
sigfox.close()
return True
# Sending Format of data - bytes order - required (True for BigEndian, False for LittleEndian)
# for sending to actoboard.com : LittleEndian (i.e. False) is expected for received data
sendingFormat = False
# Sensor initialisation
import pyupm_tsl2561
tsl2561Ready = True
if (tsl2561Ready) :
# Instantiate a digital light sensor TSL2561 on I2C
print "initialisation TLS2561"
lightSensor = pyupm_tsl2561.TSL2561()
time.sleep (10)
# Value
numberSamples = 200
valueCount = 0
valueNow = 0
valueSum = 0
valueAvg = 0
valueMin = 32767
valueMax = 0
# Main loop
while True :
if (valueCount == numberSamples) :
print
print "after", numberSamples, "samples (values in lux):"
print "valueAvg: %5d" % valueAvg, "- valueMin: %5d" % valueMin, "- valueMax: %5d" % valueMax
print "valueAvg: ", short2hex(valueAvg,True), "- valueMin: ", short2hex(valueMin,True), "- valueMax: ", short2hex(valueMax,True)
if (sendingFormat) :
print "sending valueAvg,valueMin,valueMax (BigEndian)"
else :
print "sending valueAvg,valueMin,valueMax (LittleEndian)"
sendsigfox(short2hex(valueAvg,sendingFormat)+short2hex(valueMin,sendingFormat)+short2hex(valueMax,sendingFormat))
valueCount = 0
if (valueCount == 0) :
valueNow = 0
valueSum = 0
valueAvg = 0
valueMin = 32767
valueMax = 0
if (tsl2561Ready) :
valueNow = lightSensor.getLux()
if (valueNow >= 0) :
valueCount = valueCount + 1
valueSum = valueSum + valueNow
valueAvg = valueSum / valueCount
if valueNow < valueMin :
valueMin = valueNow
if valueNow > valueMax :
valueMax = valueNow
now = time.ctime(int(time.time()))
if (valueCount == 1) :
print
print "Light (values in lux):"
print now,"(GMT)",": %5d" % valueNow,"- avg:%5d" % valueAvg,"- min:%5d" % valueMin,"- max:%5d" % valueMax,"-%4d sample(s)" % valueCount
time.sleep(1)
exasens
Comments