├── license.txt ├── README.md ├── sendreceivesigfox.py └── sendsigfox.py /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 S.N.O.C. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rpisigfox board control script 2 | 3 | ##### Aim of this script is to control the rpisigfox board to send messages on the SigFox network. 4 | The expansion board is for raspberry pi mainboard and allows sending messages over the [SigFox network](http://sigfox.com) 5 | 6 | You can purchase the board on [YADOM.FR](http://yadom.fr/carte-rpisigfox.html). 7 | 8 | Two python scripts are provided : 9 | - sendsigfox.py sends data over the Sigfox network. 10 | - sendreceivesigfox.py sends data with a downlink message request. Downlink messages are 8 bytes long. **_Important note_** : Sigfox operators may bill downlink messages, please refer to your contract. 11 | 12 | # Usage 13 | ```bash 14 | ./sendsigfox.py MESSAGE [path/to/serial] 15 | ./sendreceivesigfox.py MESSAGE [path/to/serial] 16 | ``` 17 | #### Where: 18 | - ```MESSAGE``` is an hexadecimal encoded string; 2 to 24 characters representing 1 to 12 bytes. 19 | - ```path/to/serial``` is an optional path to the serial port, default is ```/dev/ttyAMA0```. 20 | 21 | #### Examples : 22 | - ```./sendsigfox.py 00AA55BF``` : sends the 4 bytes 0x00 0xAA 0x55 0xBF over default serial port ```/dev/ttyAMA0``` 23 | - ```./sendsigfox.py CCDD /dev/ttyS0``` : sends the 2 bytes 0xCC 0xDD over serial port ```/dev/ttyS0``` 24 | - ```./sendreceivesigfox.py 0123456789``` : sends the 5 bytes 0x01 0x23 0x45 0x67 0x89 with a downlink request over default serial port ```/dev/ttyAMA0``` 25 | 26 | # Prerequistes 27 | *The following steps should be performed in the following order* 28 | 1. Disable Raspberry Pi terminal on serial port with raspi-config utility: 29 | ```bash 30 | sudo raspi-config 31 | ``` 32 | Go to ```Interfacing Options``` then choose ```Serial``` then ```NO``` and ```OK``` 33 | 34 | 2. Install pyserial 35 | ```bash 36 | sudo apt-get install python-serial 37 | ``` 38 | 39 | 3. Download scripts 40 | - if git is installed then clone the repository : 41 | ```bash 42 | git clone https://github.com/SNOC/rpisigfox.git 43 | ``` 44 | - otherwise paste script content to a new file: 45 | ```bash 46 | nano sendsigfox.py 47 | ``` 48 | 49 | 4. Enable script execution 50 | ```bash 51 | chmod +x sendsigfox.py 52 | ``` 53 | 54 | 5. Plug antenna with its cable and send your first message: 55 | ```bash 56 | ./sendsigfox.py 0123 57 | ``` 58 | 59 | ### Pi3 specific requirements 60 | 1. Edit ```/boot/config.txt``` 61 | ```bash 62 | sudo nano /boot/config.txt 63 | ``` 64 | 1. disable if present ```dtoverlay=pi3-miniuart-bt``` by adding ```#``` character at line begining : 65 | ```#dtoverlay=pi3-miniuart-bt``` 66 | 2. if not present, add : 67 | ```bash 68 | dtoverlay=pi3-disable-bt 69 | enable_uart=1 70 | ``` 71 | *note: ```enable_uart=0``` might be present at the end of the file, in such case it should be commented or modified to ```enable_uart=1```* 72 | 73 | 2. then reboot : 74 | ```bash 75 | sudo reboot 76 | ``` 77 | Serial port to use is the script's default one : ```/dev/ttyAMA0``` 78 | 79 | ##### License 80 | 81 | MIT License / read license.txt 82 | -------------------------------------------------------------------------------- /sendreceivesigfox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ## @package rpisigfox 4 | # This script allow the control of the rpisigfox expansion board for Raspberry Pi. 5 | # 6 | # V1.0 allow only to send regular message on the SigFox Network. 7 | # syntax is : 8 | # sendsigfox MESSAGE 9 | # where MESSAGE is an HEXA string encoded. Can be 2 to 24 characters representing 1 to 12 bytes. 10 | # Example : sendsigfox 00AA55BF to send the 4 bytes 0x00 0xAA 0x55 0xBF 11 | # 12 | 13 | import time 14 | import serial 15 | import sys 16 | import re 17 | from time import sleep 18 | 19 | SOH = chr(0x01) 20 | STX = chr(0x02) 21 | EOT = chr(0x04) 22 | ACK = chr(0x06) 23 | NAK = chr(0x15) 24 | CAN = chr(0x18) 25 | CRC = chr(0x43) 26 | 27 | def getc(size, timeout=1): 28 | return ser.read(size) 29 | 30 | def putc(data, timeout=1): 31 | ser.write(data) 32 | sleep(0.001) # give device time to prepare new buffer and start sending it 33 | 34 | def WaitFor(ser, success, failure, timeOut): 35 | return ReceiveUntil(ser, success, failure, timeOut) != '' 36 | 37 | def ReceiveUntil(ser, success, failure, timeOut): 38 | iterCount = timeOut / 0.1 39 | ser.timeout = 0.1 40 | currentMsg = '' 41 | while iterCount >= 0 and success not in currentMsg and failure not in currentMsg : 42 | sleep(0.1) 43 | while ser.inWaiting() > 0 : 44 | c = ser.read() 45 | currentMsg += c 46 | iterCount -= 1 47 | if success in currentMsg : 48 | return currentMsg 49 | elif failure in currentMsg : 50 | print 'Failure (' + currentMsg.replace('\r\n', '') + ')' 51 | else : 52 | print 'Receive timeout (' + currentMsg.replace('\r\n', '') + ')' 53 | return '' 54 | 55 | print 'Sending SigFox Message...' 56 | 57 | # allow serial port choice from parameter - default is /dev/ttyAMA0 58 | portName = '/dev/ttyAMA0' 59 | if len(sys.argv) == 3: 60 | portName = sys.argv[2] 61 | 62 | print 'Serial port : ' + portName 63 | 64 | ser = serial.Serial( 65 | port=portName, 66 | baudrate=9600, 67 | parity=serial.PARITY_NONE, 68 | stopbits=serial.STOPBITS_ONE, 69 | bytesize=serial.EIGHTBITS 70 | ) 71 | 72 | if ser.isOpen() : # on some platforms the serial port needs to be closed first 73 | ser.close() 74 | 75 | try: 76 | ser.open() 77 | except serial.SerialException as e: 78 | sys.stderr.write("Could not open serial port {}: {}\n".format(ser.name, e)) 79 | sys.exit(1) 80 | 81 | ser.write('AT\r') 82 | if WaitFor(ser, 'OK', 'ERROR', 3) : 83 | print('SigFox Modem OK') 84 | else: 85 | print('SigFox Modem Init Error') 86 | ser.close() 87 | exit() 88 | 89 | ser.write('ATE0\r') 90 | if WaitFor(ser, 'OK', 'ERROR', 3) : 91 | print('SigFox Modem echo OFF') 92 | else: 93 | print('SigFox Modem Configuration Error') 94 | ser.close() 95 | exit() 96 | 97 | ser.write("AT$SF={0},2,1\r".format(sys.argv[1])) 98 | print('Sending ...') 99 | if WaitFor(ser, 'OK', 'ERROR', 25) : 100 | print('Message sent') 101 | else: 102 | print('Error sending message') 103 | ser.close() 104 | exit() 105 | 106 | if WaitFor(ser, 'BEGIN', 'ERROR', 25) : 107 | print('Waiting for answer') 108 | else: 109 | print('Error waiting for answer') 110 | ser.close() 111 | exit() 112 | 113 | rxData = ReceiveUntil(ser, 'END', 'ERROR', 25) 114 | if rxData != '' : 115 | print('Answer received') 116 | else: 117 | print('Error receiving answer') 118 | ser.close() 119 | exit() 120 | 121 | print re.sub(r'\+RX=([0-9af ]{2,})\+RX END', r'\1', rxData.replace('\r\n', '')) 122 | 123 | ser.close() 124 | -------------------------------------------------------------------------------- /sendsigfox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ## @package rpisigfox 4 | # This script allow the control of the rpisigfox expansion board for Raspberry Pi. 5 | # 6 | # V1.0 allow only to send regular message on the SigFox Network. 7 | # syntax is : 8 | # sendsigfox MESSAGE 9 | # where MESSAGE is a HEXA string encoded. Can be 2 to 24 characters representing 1 to 12 bytes. 10 | # Example : sendsigfox 00AA55BF to send the 4 bytes 0x00 0xAA 0x55 0xBF 11 | # 12 | 13 | import time 14 | import serial 15 | import sys 16 | from time import sleep 17 | 18 | class Sigfox(object): 19 | SOH = chr(0x01) 20 | STX = chr(0x02) 21 | EOT = chr(0x04) 22 | ACK = chr(0x06) 23 | NAK = chr(0x15) 24 | CAN = chr(0x18) 25 | CRC = chr(0x43) 26 | 27 | def __init__(self, port): 28 | # allow serial port choice from parameter - default is /dev/ttyAMA0 29 | portName = port 30 | 31 | print 'Serial port : ' + portName 32 | self.ser = serial.Serial( 33 | port=portName, 34 | baudrate=9600, 35 | parity=serial.PARITY_NONE, 36 | stopbits=serial.STOPBITS_ONE, 37 | bytesize=serial.EIGHTBITS 38 | ) 39 | 40 | def getc(self, size, timeout=1): 41 | return ser.read(size) 42 | 43 | def putc(self, data, timeout=1): 44 | ser.write(data) 45 | sleep(0.001) # give device time to prepare new buffer and start sending it 46 | 47 | def WaitFor(self, success, failure, timeOut): 48 | return self.ReceiveUntil(success, failure, timeOut) != '' 49 | 50 | def ReceiveUntil(self, success, failure, timeOut): 51 | iterCount = timeOut / 0.1 52 | self.ser.timeout = 0.1 53 | currentMsg = '' 54 | while iterCount >= 0 and success not in currentMsg and failure not in currentMsg : 55 | sleep(0.1) 56 | while self.ser.inWaiting() > 0 : # bunch of data ready for reading 57 | c = self.ser.read() 58 | currentMsg += c 59 | iterCount -= 1 60 | if success in currentMsg : 61 | return currentMsg 62 | elif failure in currentMsg : 63 | print 'Failure (' + currentMsg.replace('\r\n', '') + ')' 64 | else : 65 | print 'Receive timeout (' + currentMsg.replace('\r\n', '') + ')' 66 | return '' 67 | 68 | def sendMessage(self, message): 69 | print 'Sending SigFox Message...' 70 | 71 | if(self.ser.isOpen() == True): # on some platforms the serial port needs to be closed first 72 | self.ser.close() 73 | 74 | try: 75 | self.ser.open() 76 | except serial.SerialException as e: 77 | sys.stderr.write("Could not open serial port {}: {}\n".format(ser.name, e)) 78 | sys.exit(1) 79 | 80 | self.ser.write('AT\r') 81 | if self.WaitFor('OK', 'ERROR', 3) : 82 | print('SigFox Modem OK') 83 | 84 | self.ser.write("AT$SS={0}\r".format(message)) 85 | print('Sending ...') 86 | if self.WaitFor('OK', 'ERROR', 15) : 87 | print('OK Message sent') 88 | 89 | else: 90 | print 'SigFox Modem Error' 91 | 92 | self.ser.close() 93 | 94 | if __name__ == '__main__': 95 | 96 | if len(sys.argv) == 3: 97 | portName = sys.argv[2] 98 | sgfx = Sigfox(portName) 99 | else: 100 | sgfx = Sigfox('/dev/ttyAMA0') 101 | 102 | message = "1234CAFE" 103 | if len(sys.argv) > 1: 104 | message = "{0}".format(sys.argv[1]) 105 | sgfx.sendMessage(message) 106 | #time.sleep(600) #sleep for 10 min 107 | --------------------------------------------------------------------------------