Skip to content

Instantly share code, notes, and snippets.

@samjacobson
Created April 21, 2018 10:33
Show Gist options
  • Save samjacobson/721bb301d0f2dfa17e82454b2c4b045b to your computer and use it in GitHub Desktop.
Save samjacobson/721bb301d0f2dfa17e82454b2c4b045b to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The Sigfox network allows 12 bytes per point. The PAC / id and time do not need to be included in the point payload since they are in the envelope.\n",
"\n",
"Format:\n",
" * (1) Status bits\n",
" * (.1) Reserved\n",
" * (.1) Tilt\n",
" * (.1) Digital In Long Press\n",
" * (.1) TB1=1/SA4=0 (changes following fields)\n",
" * (.1) Battery Low\n",
" * (.1) GPS Good\n",
" * (.1) Digital In / Ignition\n",
" * (.1) PTO\n",
" * (3.4) Latitude\n",
" * (3.4) Longitude\n",
" * (1) Speed\n",
" * (1) Course\n",
" * (1) Altitude\n",
" * (1) Temperature (by 0.5 degrees) -64 -> 63"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import struct\n",
"import binascii\n",
"\n",
"def packll(latitude, longitude):\n",
" assert -180 <= longitude <= 180\n",
" assert -90 <= latitude <= 90\n",
" latitude = int((latitude + 180) * 600000)\n",
" longitude = int((longitude + 180) * 600000)\n",
" b0 = (latitude >> 20) & 0xff\n",
" b1 = (latitude >> 12) & 0xff\n",
" b2 = (latitude >> 4) & 0xff\n",
" b3 = (latitude & 0x0f) << 4\n",
" b3 |= (longitude >> 24) & 0x0f\n",
" b4 = (longitude >> 16) & 0xff\n",
" b5 = (longitude >> 8) & 0xff\n",
" b6 = longitude & 0xff\n",
" return struct.pack('>BBBBBBB', b0, b1, b2, b3, b4, b5, b6)\n",
"\n",
"def clamp(val, mn, mx):\n",
" if val < mn:\n",
" return mn\n",
" if val > mx:\n",
" return mx\n",
" return val\n",
"\n",
"def encode(data):\n",
" speed = clamp(int(data['speed']), 0, 255)\n",
" course = clamp(int(data['course']), 0, 359) // 2\n",
" altitude = clamp(int(data['altitude']), 0, 1023) // 8\n",
" temperature = clamp(int(data['temperature'] * 2 + 0.5), -128, 127) + 128\n",
" status = 0\n",
" if data.get('battLow'): status |= 0x08\n",
" if data.get('gpsGood'): status |= 0x04\n",
" if data.get('ignition'): status |= 0x02\n",
" if data.get('pto'): status |= 0x01\n",
" ret = struct.pack('B', status)\n",
" ret += packll(data['latitude'], data['longitude'])\n",
" ret += struct.pack('BBBB', speed, course, altitude, temperature)\n",
" return binascii.hexlify(ret)\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def unpackll(ll):\n",
" b0, b1, b2, b3, b4, b5, b6 = map(int, ll)\n",
" latitude = (b0 << 20) | (b1 << 12) | (b2 << 4) | (b3 >> 4)\n",
" longitude = (b3 & 0x0f) << 24 | (b4 << 16) | (b5 << 8) | b6\n",
" latitude = (float(latitude) / 600000) - 180\n",
" longitude = (float(longitude) / 600000) - 180\n",
" return latitude, longitude\n",
"\n",
"def decode(payload):\n",
" data = {}\n",
" payload = binascii.unhexlify(payload)\n",
" data['latitude'], data['longitude'] = unpackll(payload[1:8])\n",
" data['speed'] = int(payload[8])\n",
" data['course'] = int(payload[9]) * 2\n",
" data['altitude'] = int(payload[10]) * 8\n",
" data['temperature'] = float(payload[11]) / 2 - 64\n",
" status = payload[0]\n",
" data['battLow'] = bool(status & 0x08)\n",
" data['gpsGood'] = bool(status & 0x04)\n",
" data['ignition'] = bool(status & 0x02) # Digital Input on TBSA\n",
" data['pto'] = bool(status & 0x01)\n",
" return data\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'0151736bccaa18b8201e0b98'\n",
"{'latitude': -37.654300000000006, 'longitude': 174.1234, 'speed': 32, 'course': 60, 'altitude': 88, 'temperature': 12.0, 'battLow': False, 'gpsGood': False, 'ignition': False, 'pto': True}\n"
]
}
],
"source": [
"data = {\n",
" 'latitude': -37.6543,\n",
" 'longitude': 174.1234,\n",
" 'speed': 32,\n",
" 'course': 60,\n",
" 'altitude': 88,\n",
" 'temperature': 12.2,\n",
" 'pto': True\n",
"}\n",
"payload = encode(data)\n",
"print(payload)\n",
"dec = decode(payload)\n",
"print(dec)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'latitude': -36.897115000000014, 'longitude': 174.77469000000002, 'speed': 12, 'course': 296, 'altitude': 224, 'temperature': 23.5, 'battLow': False, 'gpsGood': True, 'ignition': False, 'pto': False}\n"
]
}
],
"source": [
"print(decode(b'0451e2563cb00f2e0c941caf'))"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'latitude': -36.897099999999995, 'longitude': 174.77464500000002, 'speed': 1, 'course': 166, 'altitude': 248, 'temperature': 22.5, 'battLow': False, 'gpsGood': True, 'ignition': False, 'pto': False}\n"
]
}
],
"source": [
"print(decode(b'0451e256ccb00f1301531fad'))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment