Compare commits
9 Commits
5dc3587ccb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
001b280936 | ||
|
|
c8b49be7ff | ||
|
|
24274e3f3a | ||
|
|
d3aae7368c | ||
|
|
cf51b0da69 | ||
|
|
d39b4e8494 | ||
|
|
4162cead3d | ||
|
|
4a8b2474b8 | ||
|
|
d86cd5b72e |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
config.ini
|
||||||
19
README.md
19
README.md
@@ -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
3
config.ini
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[Default]
|
||||||
|
AppId=app_id
|
||||||
|
AccessKey=ttn-account-v2.redacted
|
||||||
134
main.py
134
main.py
@@ -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)
|
||||||
|
|||||||
@@ -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
17
tests.py
Normal 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) + "}")
|
||||||
Reference in New Issue
Block a user