Compare commits

...

9 Commits

Author SHA1 Message Date
matt
001b280936 update readme 2020-05-29 12:06:46 -07:00
matt
c8b49be7ff update readme 2020-05-29 12:05:56 -07:00
matt
24274e3f3a update readme 2020-05-29 12:04:43 -07:00
sessionm21
d3aae7368c Add sending to collar 2020-05-16 02:25:10 +01:00
sessionm21
cf51b0da69 store stimulus information 2020-05-13 06:36:23 +01:00
sessionm21
d39b4e8494 update protobuf 2020-05-13 04:14:23 +01:00
sessionm21
4162cead3d add gitignore 2020-05-12 22:11:58 +01:00
sessionm21
4a8b2474b8 move keys to config file 2020-05-12 22:11:33 +01:00
sessionm21
d86cd5b72e seperate the tests 2020-05-12 22:01:21 +01:00
6 changed files with 158 additions and 17 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
config.ini

View File

@@ -5,4 +5,21 @@
# Generate files from .proto file # Generate files from .proto file
```protoc -I=./ --python_out=./ message.proto``` ```
protoc -I=./ --python_out=./ message.proto
```
# Make the config.ini file
Following this format create a config.ini file.
```
[Default]
AppId=<redacted>
AccessKey=ttn-account-v2.<redacted>
```
# Run the Gateway
After generating the protobuf files and making a config.ini file one can simply run:
```python3 main.py```

3
config.ini Normal file
View File

@@ -0,0 +1,3 @@
[Default]
AppId=app_id
AccessKey=ttn-account-v2.redacted

134
main.py
View File

@@ -4,28 +4,91 @@ import base64
import message_pb2 import message_pb2
import sqlite3 import sqlite3
app_id = "fenceles_grazing" import time
access_key = "ttn-account-v2.XVvtBVcWzkeby-fe9eLtiJBLRbjQR-b358S4z70Xa-0" import configparser
config = configparser.ConfigParser()
config.read("config.ini")
app_id = config['Default']['AppId']
access_key = config['Default']['AccessKey']
# For now use collar id of 1, should look up collar id based on collarname from db # For now use collar id of 1, should look up collar id based on collarname from db
def store_coord(collarname, x, y): def store_collar_data(collarname, res):
print("Coord {x: " + str(x) + ", y: " + str(y) + "}") print("Coord {x: " + str(res.loc.x) + ", y: " + str(res.loc.y) + "}")
db = sqlite3.connect('data.sqlite') db = sqlite3.connect('data.sqlite')
entries = [(1, x, y)]
db.executemany("INSERT INTO data_point (collar_id, longitude, latitude, datetime) VALUES (?,?,?,datetime('now'))", entries) entries = [(1, res.loc.y, res.loc.x)]
db.executemany(
"INSERT INTO data_point (collar_id, longitude, latitude, datetime) VALUES (?,?,?,datetime('now'))",
entries)
db.commit() db.commit()
if(res.oob == 1):
entries = [(1, res.loc.y, res.loc.x)]
db.executemany(
"INSERT INTO stimulus_activation (collar_id, longitude, latitude, datetime) VALUES (?,?,?,datetime('now'))",
entries)
db.commit()
db.close() db.close()
def boundary_get_coord(self, key):
if key == 0: return self.coord0
if key == 1: return self.coord1
if key == 2: return self.coord2
if key == 3: return self.coord3
if key == 4: return self.coord4
if key == 5: return self.coord5
if key == 6: return self.coord6
if key == 7: return self.coord7
if key == 8: return self.coord8
if key == 9: return self.coord9
message_pb2.Coordinates.__getitem__ = boundary_get_coord
def pack_boundary(boundary):
coordinates = message_pb2.Coordinates()
coordinates.isr = boundary[2]
for i in range(boundary[2]):
coordinates[i].x = boundary[4 + 2*i]
coordinates[i].y = boundary[5 + 2*i]
for i in range(boundary[2], 10):
coordinates[i].x = 1.0
coordinates[i].y = 1.0
return coordinates
def push_coordinate(id, packed):
payload = {
'port': 1,
'confirmed': False,
'payload_raw': base64.b64encode(packed.SerializeToString())
}
print("Pushing coordinate", packed)
print("Device ID:", id)
print("Payload:", json.dumps(payload))
client.publish(app_id+"/devices/" + 'fenceless' + "/down", json.dumps(payload))
def find_new_boundaries():
db = sqlite3.connect('data.sqlite')
bounds = db.execute("SELECT * from bounding_box where needs_push=1").fetchall()
for bound in bounds:
print("Found boundary. ID:", bound[0])
push_coordinate(bound[1], pack_boundary(bound))
db.execute("UPDATE bounding_box set needs_push=0 where id=?", (bound[0],))
db.commit()
connected = False
# The callback for when the client receives a CONNACK response from the server. # The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc): def on_connect(client, userdata, flags, rc):
global connected
connected = True
print("Connected with result code "+str(rc)) print("Connected with result code "+str(rc))
# Subscribing in on_connect() means that if we lose the connection and # Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed. # reconnect then subscriptions will be renewed.
# client.subscribe("+/devices/+/events/activations") # client.subscribe("+/devices/+/events/activations")
client.subscribe("+/devices/+/up") client.subscribe("+/devices/+/up")
client.publish(appid+"/devices/+/down", "hello world") client.publish(app_id+"/devices/+/down", "hello world")
# The callback for when a PUBLISH message is received from the server. # The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg): def on_message(client, userdata, msg):
@@ -39,15 +102,47 @@ def on_message(client, userdata, msg):
bcode = base64.b64decode(code) bcode = base64.b64decode(code)
res = message_pb2.CollarResponse() res = message_pb2.CollarResponse()
res.ParseFromString(bcode) res.ParseFromString(bcode)
store_coord(payload['dev_id'], res.loc.x, res.loc.y) # store_collar_data(payload['dev_id'], res.loc.x, res.loc.y)
store_collar_data(payload['dev_id'], res)
# Test protobuf here
# code = bytearray('CgoNAAAAABUAAAAA', "utf-8") coordinates = message_pb2.Coordinates()
# print(code) coordinates.isr = 4
# bcode = base64.b64decode(code)
# res = message_pb2.CollarResponse() coordinates.coord0.x = 0
# res.ParseFromString(bcode) coordinates.coord1.x = 1
# print("Coord {x: " + str(res.loc.x) + ", y: " + str(res.loc.y) + "}") coordinates.coord2.x = 0
coordinates.coord3.x = 1
coordinates.coord0.y = 1
coordinates.coord1.y = 1
coordinates.coord2.y = 0
coordinates.coord3.y = 0
# coordinates.coord0.x = 44.5934295644297
# coordinates.coord1.x = 44.5934295644297
# coordinates.coord2.x = 44.5934295664297
# coordinates.coord3.x = 44.5934295664297
#
# coordinates.coord0.y = -123.306968698965
# coordinates.coord1.y = -123.306968678965
# coordinates.coord2.y = -123.306968678965
# coordinates.coord3.y = -123.306968698965
coordinates.coord4.x = 1
coordinates.coord5.x = 1
coordinates.coord6.x = 1
coordinates.coord7.x = 1
coordinates.coord8.x = 1
coordinates.coord9.x = 1
coordinates.coord4.y = 2
coordinates.coord5.y = 2
coordinates.coord6.y = 2
coordinates.coord7.y = 2
coordinates.coord8.y = 2
coordinates.coord9.y = 2
# SerializeToString()
print(base64.b64encode(coordinates.SerializeToString()))
client = mqtt.Client() client = mqtt.Client()
client.on_connect = on_connect client.on_connect = on_connect
@@ -60,4 +155,11 @@ client.connect("us-west.thethings.network", 1883, 60)
# handles reconnecting. # handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a # Other loop*() functions are available that give a threaded interface and a
# manual interface. # manual interface.
client.loop_forever() client.loop_start()
while not connected:
time.sleep(0.1)
print("Starting boundary checking work.")
while True:
find_new_boundaries()
time.sleep(10)

View File

@@ -9,6 +9,7 @@ message Coordinate {
message CollarResponse { message CollarResponse {
required Coordinate loc = 1; required Coordinate loc = 1;
required int32 oob = 2;
} }
message Coordinates { message Coordinates {

17
tests.py Normal file
View File

@@ -0,0 +1,17 @@
import paho.mqtt.client as mqtt
import json
import base64
import message_pb2
import sqlite3
# Test protobuf here
code = bytearray('CgoNAABIQxUAAMhCEAA=', "utf-8")
print(code)
bcode = base64.b64decode(code)
res = message_pb2.CollarResponse()
res.ParseFromString(bcode)
assert res.loc.x == 200
assert res.loc.y == 100
assert res.oob == 0
print("Coord {x: " + str(res.loc.x) + ", y: " + str(res.loc.y) + "}")