Commit 7e6be93195f889c3f6ef8959bee066448b71d4ec
1 parent
fe4b6547c6
Exists in
master
gateway commit
Showing 9 changed files with 773 additions and 0 deletions Side-by-side Diff
gw_RPi3/README
| 1 | +pi@192.168.1.180 : raspberry |
gw_RPi3/config.txt
| 1 | +# For more options and information see | |
| 2 | +# http://rpf.io/configtxt | |
| 3 | +# Some settings may impact device functionality. See link above for details | |
| 4 | + | |
| 5 | +# uncomment if you get no picture on HDMI for a default "safe" mode | |
| 6 | +#hdmi_safe=1 | |
| 7 | + | |
| 8 | +# uncomment this if your display has a black border of unused pixels visible | |
| 9 | +# and your display can output without overscan | |
| 10 | +#disable_overscan=1 | |
| 11 | + | |
| 12 | +# uncomment the following to adjust overscan. Use positive numbers if console | |
| 13 | +# goes off screen, and negative if there is too much border | |
| 14 | +#overscan_left=16 | |
| 15 | +#overscan_right=16 | |
| 16 | +#overscan_top=16 | |
| 17 | +#overscan_bottom=16 | |
| 18 | + | |
| 19 | +# uncomment to force a console size. By default it will be display's size minus | |
| 20 | +# overscan. | |
| 21 | +#framebuffer_width=1280 | |
| 22 | +#framebuffer_height=720 | |
| 23 | + | |
| 24 | +# uncomment if hdmi display is not detected and composite is being output | |
| 25 | +#hdmi_force_hotplug=1 | |
| 26 | + | |
| 27 | +# uncomment to force a specific HDMI mode (this will force VGA) | |
| 28 | +#hdmi_group=1 | |
| 29 | +#hdmi_mode=1 | |
| 30 | + | |
| 31 | +# uncomment to force a HDMI mode rather than DVI. This can make audio work in | |
| 32 | +# DMT (computer monitor) modes | |
| 33 | +#hdmi_drive=2 | |
| 34 | + | |
| 35 | +# uncomment to increase signal to HDMI, if you have interference, blanking, or | |
| 36 | +# no display | |
| 37 | +#config_hdmi_boost=4 | |
| 38 | + | |
| 39 | +# uncomment for composite PAL | |
| 40 | +#sdtv_mode=2 | |
| 41 | + | |
| 42 | +#uncomment to overclock the arm. 700 MHz is the default. | |
| 43 | +#arm_freq=800 | |
| 44 | + | |
| 45 | +# Uncomment some or all of these to enable the optional hardware interfaces | |
| 46 | +dtparam=i2c_arm=on | |
| 47 | +#dtparam=i2s=on | |
| 48 | +dtparam=spi=on | |
| 49 | +dtparam=i2c1=on, dtparam=i2c_arm_baudrate=100000 | |
| 50 | + | |
| 51 | +# Uncomment this to enable the lirc-rpi module | |
| 52 | +#dtoverlay=lirc-rpi | |
| 53 | + | |
| 54 | +# Additional overlays and parameters are documented /boot/overlays/README | |
| 55 | + | |
| 56 | +# Enable audio (loads snd_bcm2835) | |
| 57 | +dtparam=audio=on | |
| 58 | +dtoverlay=disable-bt | |
| 59 | +dtoverlay=i2c1 |
gw_RPi3/python/Endpoint.py
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# -*- coding: utf-8 -*- | |
| 3 | +""" | |
| 4 | +Created on Wed Jun 9 11:15:10 2021 | |
| 5 | + | |
| 6 | +@author: Georges de Massol | |
| 7 | +""" | |
| 8 | +import base64 | |
| 9 | +#import binascii | |
| 10 | + | |
| 11 | +class Endpoint: | |
| 12 | + def __init__(self, EUI = None): | |
| 13 | + """ | |
| 14 | + | |
| 15 | + Parameters | |
| 16 | + ---------- | |
| 17 | + EUI : bytes | |
| 18 | + ex : bytes([0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) | |
| 19 | + | |
| 20 | + Returns | |
| 21 | + ------- | |
| 22 | + None. | |
| 23 | + | |
| 24 | + """ | |
| 25 | + # This must point to the API interface. | |
| 26 | + self.EUI = EUI | |
| 27 | + | |
| 28 | + #EUI = bytes([0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) | |
| 29 | + def EUIfromjson(self, json): | |
| 30 | + self.EUI = base64.b64decode(json["devEUI"]).hex() | |
| 31 | + return self.EUI | |
| 32 | + |
gw_RPi3/python/gat.py
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# -*- coding: utf-8 -*- | |
| 3 | +""" | |
| 4 | +Do not execute directly. | |
| 5 | +Please execute gateway_http_uplink.py | |
| 6 | + | |
| 7 | +Created on Mon Oct 19 2021 | |
| 8 | + | |
| 9 | +@author: ALKADRI Mohammad | |
| 10 | +""" | |
| 11 | + | |
| 12 | +from gateway_http_downlink import Downlink | |
| 13 | + | |
| 14 | +from Endpoint import Endpoint | |
| 15 | + | |
| 16 | +import time | |
| 17 | +from datetime import datetime | |
| 18 | +import os | |
| 19 | +import json | |
| 20 | +import base64 | |
| 21 | + | |
| 22 | + | |
| 23 | +APIKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcGlfa2V5X2lkIjoiYzA2ZGY1MDMtNjE5Zi00ZjI2LTgxNzEtYTU0OTRmMWJmYmRmIiwiYXVkIjoiYXMiLCJpc3MiOiJhcyIsIm5iZiI6MTYyMjY1MzMzMSwic3ViIjoiYXBpX2tleSJ9.23eLyvgd5zheP9hDM0acCAl9ojhQjLTZAU77IKqhvQY' | |
| 24 | +server = 'localhost:8080' | |
| 25 | +#just defining an instance to be used | |
| 26 | +downlink = Downlink(server, APIKey) | |
| 27 | +directory = '/home/pi/python/' | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | +def WriteFile(body, event): | |
| 32 | + filename = directory + "log/" + \ | |
| 33 | + time.strftime("%Y_%m_%d_%H-%M-%S") + '_' + event | |
| 34 | + # in case of unexisting folder 'log' | |
| 35 | + if not os.path.exists(directory + 'log'): | |
| 36 | + os.mkdir(directory + 'log') | |
| 37 | + # in case of already existing file : | |
| 38 | + if os.path.exists(filename + ".json"): | |
| 39 | + i = 2 | |
| 40 | + while(os.path.exists(filename + '_' + str(i) + ".json")): | |
| 41 | + i += 1 | |
| 42 | + path = filename + '_' + str(i) + ".json" | |
| 43 | + else: | |
| 44 | + path = filename + ".json" | |
| 45 | + | |
| 46 | + f = open(path, "a") | |
| 47 | + f.write(body.decode("utf-8")) | |
| 48 | + f.close() | |
| 49 | + print("file written : %s" % path) | |
| 50 | + | |
| 51 | + | |
| 52 | +def step0(endpoint): | |
| 53 | + downlink.FlushQueue(endpoint.EUI) | |
| 54 | + downlink.Lorasend(endpoint.EUI, b'\x46') | |
| 55 | + print("State: The data sent by Gateway") | |
| 56 | + | |
| 57 | + | |
| 58 | +def step1(endpoint): | |
| 59 | + T3 = 222333 | |
| 60 | + T4 = 1112223 | |
| 61 | + print ("T3 : %s" % T3.to_bytes(4, 'big')) | |
| 62 | + print ("T4 : %s" % T4.to_bytes(4, 'big')) | |
| 63 | + T = T4 << 32| T3 | |
| 64 | + print ("T : %s" % T) | |
| 65 | + print ("T : %s" % T.to_bytes(8, 'big')) | |
| 66 | + downlink.FlushQueue(endpoint.EUI) | |
| 67 | + # send all data | |
| 68 | + downlink.Lorasend(endpoint.EUI, T.to_bytes(8, 'big')) | |
| 69 | + | |
| 70 | + | |
| 71 | +def reset(endpoint): | |
| 72 | + downlink.FlushQueue(endpoint.EUI) | |
| 73 | + downlink.Lorasend(endpoint.EUI, b'\x55') #initialisation packet | |
| 74 | + print("enpoint reset : %s" % endpoint.EUI) | |
| 75 | + | |
| 76 | + | |
| 77 | +def postcompute(event, body, Tn): | |
| 78 | + global data | |
| 79 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 80 | + | |
| 81 | + json_ = json.loads(body) | |
| 82 | + endpoint = Endpoint() | |
| 83 | + endpoint.EUIfromjson(json_) | |
| 84 | + | |
| 85 | + print("request from :\nEUI : %s" % endpoint.EUI) | |
| 86 | + print("name : %s" % json_['deviceName']) | |
| 87 | + # write json in a file | |
| 88 | + WriteFile(body, event) | |
| 89 | + | |
| 90 | + print("event : %s " % event) | |
| 91 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 92 | + #treat all cases | |
| 93 | + if event == 'up': | |
| 94 | + #b64 to bytes | |
| 95 | + data = base64.b64decode(json_["data"]) | |
| 96 | + #bytes to integer | |
| 97 | + #integer = int.from_bytes(data, 'big') | |
| 98 | + print("data received from Endpoint : ") | |
| 99 | + print("base 64 : %s" % json_["data"]) | |
| 100 | + print("bytes : %s" % data) | |
| 101 | + #print("int : %s" % integer) | |
| 102 | + print() | |
| 103 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 104 | + data = int.from_bytes(data, 'big') | |
| 105 | + print("data : %s" % data) | |
| 106 | + print("fin") | |
| 107 | + elif event == 'txack': | |
| 108 | + print("data : %s" % data) | |
| 109 | + if data == 0x5374617274 : # 0x5374617274 : Start | |
| 110 | + step0(endpoint) | |
| 111 | + elif data == 0x54696D6573: # 0x54696D6573 : Times | |
| 112 | + step1(endpoint) | |
| 113 | + else: | |
| 114 | + print("error : uncovered State") | |
| 115 | + reset(endpoint) | |
| 116 | + elif event == 'error': | |
| 117 | + print('error : ' + json_["error"]) | |
| 118 | + else: | |
| 119 | + print("possible error : uncovered event") | |
| 120 | + print(body) | |
| 121 | + reset(endpoint) | |
| 122 | + print() | |
| 123 | + | |
| 124 | +print("Chirpstack server for downlink : %s" % downlink.server) |
gw_RPi3/python/gate.py
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# -*- coding: utf-8 -*- | |
| 3 | +""" | |
| 4 | +Do not execute directly. | |
| 5 | +Please execute gateway_http_downlink.py | |
| 6 | + | |
| 7 | +Created on Tue Jun 8 16:37:22 2021 | |
| 8 | + | |
| 9 | +@author: Georges de Massol | |
| 10 | +""" | |
| 11 | + | |
| 12 | +from gateway_http_downlink import Downlink | |
| 13 | + | |
| 14 | +from Endpoint import Endpoint | |
| 15 | + | |
| 16 | +import time | |
| 17 | +from datetime import datetime | |
| 18 | +import os | |
| 19 | +import json | |
| 20 | +import base64 | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | +APIKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcGlfa2V5X2lkIjoiYzA2ZGY1MDMtNjE5Zi00ZjI2LTgxNzEtYTU0OTRmMWJmYmRmIiwiYXVkIjoiYXMiLCJpc3MiOiJhcyIsIm5iZiI6MTYyMjY1MzMzMSwic3ViIjoiYXBpX2tleSJ9.23eLyvgd5zheP9hDM0acCAl9ojhQjLTZAU77IKqhvQY' | |
| 25 | +server = 'localhost:8080' | |
| 26 | +#just defining an instance to be used | |
| 27 | +downlink = Downlink(server, APIKey) | |
| 28 | +directory = '/home/pi/python/' | |
| 29 | + | |
| 30 | + | |
| 31 | +State = 0 | |
| 32 | + | |
| 33 | +def WriteFile(body, event): | |
| 34 | + filename = directory + "log/" + \ | |
| 35 | + time.strftime("%Y_%m_%d_%H-%M-%S") + '_' + event | |
| 36 | + # in case of unexisting folder 'log' | |
| 37 | + if not os.path.exists(directory + 'log'): | |
| 38 | + os.mkdir(directory + 'log') | |
| 39 | + # in case of already existing file : | |
| 40 | + if os.path.exists(filename + ".json"): | |
| 41 | + i = 2 | |
| 42 | + while(os.path.exists(filename + '_' + str(i) + ".json")): | |
| 43 | + i += 1 | |
| 44 | + path = filename + '_' + str(i) + ".json" | |
| 45 | + else: | |
| 46 | + path = filename + ".json" | |
| 47 | + | |
| 48 | + f = open(path, "a") | |
| 49 | + f.write(body.decode("utf-8")) | |
| 50 | + f.close() | |
| 51 | + print("file written : %s" % path) | |
| 52 | + | |
| 53 | + | |
| 54 | +def step0(Tn, endpoint): | |
| 55 | + global T2, State | |
| 56 | + print("Last State sss : %s" % State) | |
| 57 | + if State != 0: | |
| 58 | + print("probable error : message unexpected :") | |
| 59 | + print("Last State sss : %s" % State) | |
| 60 | + print("Current State : 0") | |
| 61 | + #reset() | |
| 62 | + T2 = Tn | |
| 63 | + State = 0 | |
| 64 | + | |
| 65 | +def step1(data, endpoint): | |
| 66 | + global T3, State, dTg | |
| 67 | + T3 = data | |
| 68 | + State = 1 | |
| 69 | + | |
| 70 | + #time spent by gateway between uplink and downlink | |
| 71 | + dTg = T3+1 | |
| 72 | + print ("Tg : %s" % dTg.to_bytes(4, 'big')) | |
| 73 | + downlink.FlushQueue(endpoint.EUI) | |
| 74 | + # send all data for step 3 | |
| 75 | + downlink.Lorasend(endpoint.EUI, b'\x01' + dTg.to_bytes(4, 'big')) | |
| 76 | + | |
| 77 | +def step2(endpoint, data): | |
| 78 | + global State | |
| 79 | + | |
| 80 | + if State != 1: | |
| 81 | + print("probable error : message unexpected :") | |
| 82 | + print("Last State : %s" % State) | |
| 83 | + print("Current State : 2") | |
| 84 | + reset() | |
| 85 | + | |
| 86 | + State = 2 | |
| 87 | + | |
| 88 | + dTe = int.from_bytes(data, 'big') | |
| 89 | + dTv = (dTe - dTg)/2 | |
| 90 | + print("time of flight (samples number) : %s" % dTv) | |
| 91 | + print("time of flight (microseconds) : %s" % (dTv * 0.0005)) ## 1 sample = 500ns | |
| 92 | + | |
| 93 | +def step3(endpoint): | |
| 94 | + global State | |
| 95 | + State = 3 | |
| 96 | + | |
| 97 | + #reset the endpoint | |
| 98 | + reset(endpoint) | |
| 99 | + | |
| 100 | +def reset(endpoint): | |
| 101 | + global State | |
| 102 | + downlink.FlushQueue(endpoint.EUI) | |
| 103 | + downlink.Lorasend(endpoint.EUI, b'\x55')#initialisation packet | |
| 104 | + print("enpoint reset : %s" % endpoint.EUI) | |
| 105 | + State = 0 | |
| 106 | +def postcompute(event, body, Tn): | |
| 107 | + print("D") | |
| 108 | + global data | |
| 109 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 110 | + | |
| 111 | + json_ = json.loads(body) | |
| 112 | + endpoint = Endpoint() | |
| 113 | + endpoint.EUIfromjson(json_) | |
| 114 | + | |
| 115 | + print("request from :\nEUI : %s" % endpoint.EUI) | |
| 116 | + print("name : %s" % json_['deviceName']) | |
| 117 | + # write json in a file | |
| 118 | + WriteFile(body, event) | |
| 119 | + | |
| 120 | + | |
| 121 | + print("event : %s " % event) | |
| 122 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 123 | + #treat all cases | |
| 124 | + if event == 'up': | |
| 125 | + #b64 to bytes | |
| 126 | + data = base64.b64decode(json_["data"]) | |
| 127 | + #bytes to integer | |
| 128 | + integer = int.from_bytes(data, 'big') | |
| 129 | + print("data received from Endpoint : ") | |
| 130 | + print("base 64 : %s" % json_["data"]) | |
| 131 | + print("bytes : %s" % data) | |
| 132 | + print("int : %s" % integer) | |
| 133 | + print() | |
| 134 | + | |
| 135 | + step = data[0] | |
| 136 | + print("step : %s" % step) | |
| 137 | + print("data : %s" % data[1:]) | |
| 138 | + if step == 0: | |
| 139 | + step0(Tn, endpoint) | |
| 140 | + elif step == 2: | |
| 141 | + step2(endpoint, data[1:]) | |
| 142 | + else: | |
| 143 | + print("error : uncovered step : %s" % step) | |
| 144 | + reset(endpoint) | |
| 145 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 146 | + data = int.from_bytes(data, 'big') | |
| 147 | + print("fin") | |
| 148 | + elif event == 'txack': | |
| 149 | + print("data sent to endpoint") | |
| 150 | + if State == 0: | |
| 151 | + step1(data, endpoint) | |
| 152 | + elif State == 2: | |
| 153 | + step3(endpoint) | |
| 154 | + else: | |
| 155 | + print('error : state %s not expected', State) | |
| 156 | + reset(endpoint) | |
| 157 | + | |
| 158 | + elif event == 'error': | |
| 159 | + print('error : ' + json_["error"]) | |
| 160 | + else: | |
| 161 | + print("possible error : uncovered event") | |
| 162 | + print(body) | |
| 163 | + reset(endpoint) | |
| 164 | + print() | |
| 165 | +print("Chirpstack server for downlink : %s" % downlink.server) |
gw_RPi3/python/gateway.py
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# -*- coding: utf-8 -*- | |
| 3 | +""" | |
| 4 | +Do not execute directly. | |
| 5 | +Please execute gateway_http_downlink.py | |
| 6 | + | |
| 7 | +Created on Tue Jun 8 16:37:22 2021 | |
| 8 | + | |
| 9 | +@author: Georges de Massol | |
| 10 | +""" | |
| 11 | + | |
| 12 | +from gateway_http_downlink import Downlink | |
| 13 | + | |
| 14 | +from Endpoint import Endpoint | |
| 15 | + | |
| 16 | +import time | |
| 17 | +from datetime import datetime | |
| 18 | +import os | |
| 19 | +import json | |
| 20 | +import base64 | |
| 21 | + | |
| 22 | + | |
| 23 | +APIKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcGlfa2V5X2lkIjoiYzA2ZGY1MDMtNjE5Zi00ZjI2LTgxNzEtYTU0OTRmMWJmYmRmIiwiYXVkIjoiYXMiLCJpc3MiOiJhcyIsIm5iZiI6MTYyMjY1MzMzMSwic3ViIjoiYXBpX2tleSJ9.23eLyvgd5zheP9hDM0acCAl9ojhQjLTZAU77IKqhvQY' | |
| 24 | +server = 'localhost:8080' | |
| 25 | +#just defining an instance to be used | |
| 26 | +downlink = Downlink(server, APIKey) | |
| 27 | +directory = '/home/pi/python/' | |
| 28 | + | |
| 29 | + | |
| 30 | +State = 0 | |
| 31 | + | |
| 32 | +def WriteFile(body, event): | |
| 33 | + filename = directory + "log/" + \ | |
| 34 | + time.strftime("%Y_%m_%d_%H-%M-%S") + '_' + event | |
| 35 | + # in case of unexisting folder 'log' | |
| 36 | + if not os.path.exists(directory + 'log'): | |
| 37 | + os.mkdir(directory + 'log') | |
| 38 | + # in case of already existing file : | |
| 39 | + if os.path.exists(filename + ".json"): | |
| 40 | + i = 2 | |
| 41 | + while(os.path.exists(filename + '_' + str(i) + ".json")): | |
| 42 | + i += 1 | |
| 43 | + path = filename + '_' + str(i) + ".json" | |
| 44 | + else: | |
| 45 | + path = filename + ".json" | |
| 46 | + | |
| 47 | + f = open(path, "a") | |
| 48 | + f.write(body.decode("utf-8")) | |
| 49 | + f.close() | |
| 50 | + print("file written : %s" % path) | |
| 51 | + | |
| 52 | + | |
| 53 | +def step0(Tn, endpoint): | |
| 54 | + global T2, State | |
| 55 | + | |
| 56 | + print("Last State sss : %s" % State) | |
| 57 | + if State != 0: | |
| 58 | + print("probable error : message unexpected :") | |
| 59 | + print("Last State sss : %s" % State) | |
| 60 | + print("Current State : 0") | |
| 61 | + #reset() | |
| 62 | + T2 = Tn | |
| 63 | + State = 0 | |
| 64 | + | |
| 65 | +State=0 | |
| 66 | +dTg=0 | |
| 67 | +T3=0 | |
| 68 | + | |
| 69 | +def step1(data, endpoint): | |
| 70 | + global T3, State, dTg | |
| 71 | + T3 = data | |
| 72 | + State = 1 | |
| 73 | + | |
| 74 | + #time spent by gateway between uplink and downlink | |
| 75 | + dTg = T3+1 | |
| 76 | + print ("Tg : %s" % dTg.to_bytes(4, 'big')) | |
| 77 | + downlink.FlushQueue(endpoint.EUI) | |
| 78 | + # send all data for step 3 | |
| 79 | + downlink.Lorasend(endpoint.EUI, b'\x01' + dTg.to_bytes(7, 'big')) | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | +def step2(endpoint, data): | |
| 84 | + global State, dTg | |
| 85 | + | |
| 86 | + if State != 1: | |
| 87 | + print("probable error : message unexpected :") | |
| 88 | + print("Last State : %s" % State) | |
| 89 | + print("Current State : 2") | |
| 90 | + reset(endpoint) | |
| 91 | + | |
| 92 | + State = 2 | |
| 93 | + | |
| 94 | + dTe = int.from_bytes(data, 'big') | |
| 95 | + dTv = (dTe - dTg)/2 | |
| 96 | + print("time of flight (samples number) : %s" % dTv) | |
| 97 | + print("time of flight (microseconds) : %s" % (dTv * 0.0005)) ## 1 sample = 500ns | |
| 98 | + | |
| 99 | +def step3(endpoint): | |
| 100 | + global State | |
| 101 | + State = 3 | |
| 102 | + | |
| 103 | + #reset the endpoint | |
| 104 | + reset(endpoint) | |
| 105 | + | |
| 106 | +def reset(endpoint): | |
| 107 | + global State | |
| 108 | + downlink.FlushQueue(endpoint.EUI) | |
| 109 | + downlink.Lorasend(endpoint.EUI, b'\x55')#initialisation packet | |
| 110 | + print("enpoint reset : %s" % endpoint.EUI) | |
| 111 | + State = 0 | |
| 112 | +def postcompute(event, body, Tn): | |
| 113 | + print("D") | |
| 114 | + global data | |
| 115 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 116 | + | |
| 117 | + json_ = json.loads(body) | |
| 118 | + endpoint = Endpoint() | |
| 119 | + endpoint.EUIfromjson(json_) | |
| 120 | + | |
| 121 | + print("request from :\nEUI : %s" % endpoint.EUI) | |
| 122 | + print("name : %s" % json_['deviceName']) | |
| 123 | + # write json in a file | |
| 124 | + WriteFile(body, event) | |
| 125 | + | |
| 126 | + print("event : %s " % event) | |
| 127 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 128 | + #treat all cases | |
| 129 | + if event == 'up': | |
| 130 | + #b64 to bytes | |
| 131 | + data = base64.b64decode(json_["data"]) | |
| 132 | + #bytes to integer | |
| 133 | + integer = int.from_bytes(data, 'big') | |
| 134 | + print("data received from Endpoint : ") | |
| 135 | + print("base 64 : %s" % json_["data"]) | |
| 136 | + print("bytes : %s" % data) | |
| 137 | + print("int : %s" % integer) | |
| 138 | + print() | |
| 139 | + | |
| 140 | + step = data[0] | |
| 141 | + print("step : %s" % step) | |
| 142 | + print("data : %s" % data[1:]) | |
| 143 | + if step == 0: | |
| 144 | + step0(Tn, endpoint) | |
| 145 | + elif step == 2: | |
| 146 | + step2(endpoint, data[1:]) | |
| 147 | + else: | |
| 148 | + print("error : uncovered step : %s" % step) | |
| 149 | + reset(endpoint) | |
| 150 | + """ | |
| 151 | + print("preparation des donnees pour envoi a la prochaine connection du EndNode") | |
| 152 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 153 | + print("message pour : %s" % endpoint.EUI) | |
| 154 | + print("message int : %s" % integer) | |
| 155 | + #send a LoRa packet | |
| 156 | + fCnt = downlink.Lorasend(endpoint.EUI, data) | |
| 157 | + # Print the downlink frame-counter value. | |
| 158 | + print("fCnt : %s" % fCnt) | |
| 159 | + """ | |
| 160 | + | |
| 161 | + print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]) | |
| 162 | + data = int.from_bytes(data, 'big') | |
| 163 | + print("fin") | |
| 164 | + elif event == 'txack': | |
| 165 | + print("data sent to endpoint") | |
| 166 | + if State == 0: | |
| 167 | + step1(data, endpoint) | |
| 168 | + elif State == 2: | |
| 169 | + step3(endpoint) | |
| 170 | + else: | |
| 171 | + print('error : state %s not expected', State) | |
| 172 | + reset(endpoint) | |
| 173 | + | |
| 174 | + elif event == 'error': | |
| 175 | + print('error : ' + json_["error"]) | |
| 176 | + else: | |
| 177 | + print("possible error : uncovered event") | |
| 178 | + print(body) | |
| 179 | + reset(endpoint) | |
| 180 | + print() | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | +# def start(): | |
| 185 | +# ok = False | |
| 186 | +# while not ok: | |
| 187 | +# try: | |
| 188 | +# Time = time.time() | |
| 189 | +# fCnt = downlink.Lorasend("70b3d549966002e1", Time) | |
| 190 | +# print(fCnt) | |
| 191 | +# time.sleep(5) | |
| 192 | +# ok = True | |
| 193 | +# except: | |
| 194 | +# pass | |
| 195 | +# | |
| 196 | +# start() | |
| 197 | + | |
| 198 | +#print ("Chirpstack API Key :\n%s" % downlink.api_token) | |
| 199 | +print("Chirpstack server for downlink : %s" % downlink.server) |
gw_RPi3/python/gateway_http_downlink.py
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# -*- coding: utf-8 -*- | |
| 3 | +""" | |
| 4 | +Created on Tue Jun 8 16:03:39 2021 | |
| 5 | + | |
| 6 | +@author: Georges de Massol | |
| 7 | +""" | |
| 8 | +import grpc | |
| 9 | +from chirpstack_api.as_pb.external import api | |
| 10 | + | |
| 11 | +class Downlink: | |
| 12 | + def __init__(self, server = "localhost:8080", api_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcGlfa2V5X2lkIjoiYzA2ZGY1MDMtNjE5Zi00ZjI2LTgxNzEtYTU0OTRmMWJmYmRmIiwiYXVkIjoiYXMiLCJpc3MiOiJhcyIsIm5iZiI6MTYyMjY1MzMzMSwic3ViIjoiYXBpX2tleSJ9.23eLyvgd5zheP9hDM0acCAl9ojhQjLTZAU77IKqhvQY'): | |
| 13 | + """ | |
| 14 | + | |
| 15 | + Parameters | |
| 16 | + ---------- | |
| 17 | + server : string, optional | |
| 18 | + Chirpstack server adress, with port. The default is "localhost:8080". | |
| 19 | + api_token : TYPE, optional | |
| 20 | + Chirpstack API token. | |
| 21 | + | |
| 22 | + Returns | |
| 23 | + ------- | |
| 24 | + None. | |
| 25 | + | |
| 26 | + """ | |
| 27 | + # This must point to the API interface. | |
| 28 | + self.server = server | |
| 29 | + | |
| 30 | + # The DevEUI for which you want to enqueue the downlink. | |
| 31 | + #dev_eui = bytes([0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) | |
| 32 | + | |
| 33 | + # The API token (retrieved using the web-interface). | |
| 34 | + self.api_token = api_token | |
| 35 | + | |
| 36 | + def Lorasend(self, dev_eui, data): | |
| 37 | + """ | |
| 38 | + | |
| 39 | + Parameters | |
| 40 | + ---------- | |
| 41 | + dev_eui : hex | |
| 42 | + The DevEUI for which you want to enqueue the downlink. | |
| 43 | + data : bytes | |
| 44 | + Data to be sent to the endpoint. | |
| 45 | + | |
| 46 | + Returns | |
| 47 | + ------- | |
| 48 | + fCnt : int | |
| 49 | + Downlink frame-counter value. | |
| 50 | + | |
| 51 | + """ | |
| 52 | + # Connect without using TLS. | |
| 53 | + channel = grpc.insecure_channel(self.server) | |
| 54 | + | |
| 55 | + # Device-queue API client. | |
| 56 | + client = api.DeviceQueueServiceStub(channel) | |
| 57 | + | |
| 58 | + # Define the API key meta-data. | |
| 59 | + auth_token = [("authorization", "Bearer %s" % self.api_token)] | |
| 60 | + | |
| 61 | + # Construct request. | |
| 62 | + req = api.EnqueueDeviceQueueItemRequest() | |
| 63 | + req.device_queue_item.confirmed = False | |
| 64 | + req.device_queue_item.data = bytes(data) | |
| 65 | + req.device_queue_item.dev_eui = dev_eui | |
| 66 | + req.device_queue_item.f_port = 10 | |
| 67 | + | |
| 68 | + resp = client.Enqueue(req, metadata=auth_token) | |
| 69 | + | |
| 70 | + return resp.f_cnt | |
| 71 | + def FlushQueue(self, dev_eui): | |
| 72 | + """ | |
| 73 | + Flush the downlink queue of an endpoint. | |
| 74 | + | |
| 75 | + Parameters | |
| 76 | + ---------- | |
| 77 | + dev_eui : hex | |
| 78 | + Endpoint EUI. | |
| 79 | + | |
| 80 | + """ | |
| 81 | + # Connect without using TLS. | |
| 82 | + channel = grpc.insecure_channel(self.server) | |
| 83 | + | |
| 84 | + # Device-queue API client. | |
| 85 | + client = api.DeviceQueueServiceStub(channel) | |
| 86 | + | |
| 87 | + # Define the API key meta-data. | |
| 88 | + auth_token = [("authorization", "Bearer %s" % self.api_token)] | |
| 89 | + | |
| 90 | + | |
| 91 | + req = api.FlushDeviceQueueRequest() | |
| 92 | + req.dev_eui = dev_eui | |
| 93 | + | |
| 94 | + client.Flush(req, metadata=auth_token) | |
| 95 | + |
gw_RPi3/python/gateway_http_uplink.py
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# -*- coding: utf-8 -*- | |
| 3 | +""" | |
| 4 | +Script to be executed. | |
| 5 | +Open a http server with function serve_forever(port) | |
| 6 | + | |
| 7 | +Created on Wed Jun 9 10:56:11 2021 | |
| 8 | + | |
| 9 | +@author: Georges de Massol | |
| 10 | +""" | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | +from http.server import HTTPServer, BaseHTTPRequestHandler | |
| 15 | +import urllib.parse | |
| 16 | +import gateway | |
| 17 | +import test_gateway | |
| 18 | +import gat | |
| 19 | +ip = 'localhost' | |
| 20 | + | |
| 21 | +class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): | |
| 22 | + def do_GET(self): | |
| 23 | + self.send_response(200) | |
| 24 | + self.end_headers() | |
| 25 | + self.wfile.write(b'Serveur uplink en marche!') | |
| 26 | + print("do_get") | |
| 27 | + | |
| 28 | + def do_POST(self): | |
| 29 | + print("do_post00") | |
| 30 | + | |
| 31 | + # ↓↓↓ Lecture de la dernière valeur de GNU Radio ↓↓↓ | |
| 32 | + # la lecture est faite le plus tôt possible pour éviter tout parasitage par un autre appareil. | |
| 33 | + | |
| 34 | + # Tn : échantillon n | |
| 35 | + Tn = 123456 | |
| 36 | + # ↑↑↑ Lecture de la dernière valeur de GNU Radio ↑↑↑ | |
| 37 | + content_length = int(self.headers['Content-Length']) | |
| 38 | + body = self.rfile.read(content_length) | |
| 39 | + self.send_response(200) | |
| 40 | + self.end_headers() | |
| 41 | + print(urllib.parse.urlparse(self.path)) | |
| 42 | + print("do_post0") | |
| 43 | + # print(urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)) | |
| 44 | + event = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query).get('event', None)[0] | |
| 45 | + print("do_post1") | |
| 46 | + gat.postcompute(event, body, Tn) | |
| 47 | + print("do_post2") | |
| 48 | + | |
| 49 | +def serve_forever(port = 6666): | |
| 50 | + """ | |
| 51 | + Function executed permanently. | |
| 52 | + Do not run code after this function. | |
| 53 | + | |
| 54 | + Parameters | |
| 55 | + ---------- | |
| 56 | + port : int, optional | |
| 57 | + Port for the server. The default is 6666. | |
| 58 | + | |
| 59 | + Returns | |
| 60 | + ------- | |
| 61 | + None. | |
| 62 | + | |
| 63 | + """ | |
| 64 | + print("d1") | |
| 65 | + | |
| 66 | + httpd = HTTPServer((ip, port), SimpleHTTPRequestHandler) | |
| 67 | + print("d2") | |
| 68 | + print("http server for uplink started on {}:{}\n".format(ip, port)) | |
| 69 | + print("d3") | |
| 70 | + httpd.serve_forever() | |
| 71 | + print("d4") | |
| 72 | + | |
| 73 | + | |
| 74 | +#do not add code then | |
| 75 | +serve_forever() |
gw_RPi3/python/test_gateway.py
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# -*- coding: utf-8 -*- | |
| 3 | +""" | |
| 4 | + | |
| 5 | +Code de test pour envoyer des requetes au gateway. | |
| 6 | + | |
| 7 | +Created on Fri Jun 11 09:12:11 2021 | |
| 8 | + | |
| 9 | +@author: Georges de Massol | |
| 10 | +""" | |
| 11 | + | |
| 12 | +import gateway as gw | |
| 13 | + | |
| 14 | +gw.server = '192.168.1.180:8080' | |
| 15 | +EUI = "70b3d549966002e1" | |
| 16 | +endpoint = gw.Endpoint(EUI) | |
| 17 | +downlink = gw.Downlink(gw.server, gw.APIKey) | |
| 18 | +#fCnt = downlink.Lorasend(endpoint.EUI, b'\x01' + int(10000).to_bytes(4, 'big')) | |
| 19 | +downlink.FlushQueue(endpoint.EUI) | |
| 20 | +print("queue flushed") | |
| 21 | +fCnt = downlink.Lorasend(endpoint.EUI, b'\x55') | |
| 22 | +print("premier paquet envoye, fCnT : %s" % fCnt) | |
| 23 | +#downlink.ResetCounter(endpoint.EUI) |