1
0
mirror of https://github.com/daniviga/bite.git synced 2024-11-24 22:06:13 +01:00

Compare commits

..

No commits in common. "c020d2c9ad28734cfc450c72d539f599c84eac96" and "da9293500194ffba0b94514aa5b180dadd6ff7b8" have entirely different histories.

28 changed files with 123 additions and 162 deletions

View File

@ -13,8 +13,6 @@ This project is for educational purposes only. It does not implement any
authentication and/or encryption protocol, so it is not suitable for real authentication and/or encryption protocol, so it is not suitable for real
production. production.
![Application Schema](./docs/application_chart.png)
## Installation ## Installation
### Requirements ### Requirements

View File

@ -55,7 +55,7 @@ struct netConfig {
} config; } config;
char serial[9]; char serial[9];
const String dpsURL = "/dps/device/subscribe/"; const String apiURL = "/api/device/subscribe/";
const String telemetryURL = "/telemetry/"; const String telemetryURL = "/telemetry/";
void setup(void) { void setup(void) {
@ -63,7 +63,7 @@ void setup(void) {
analogReference(EXTERNAL); analogReference(EXTERNAL);
StaticJsonDocument<20> dps; StaticJsonDocument<20> api;
byte mac[6]; byte mac[6];
int eeAddress = 0; int eeAddress = 0;
@ -110,8 +110,8 @@ void setup(void) {
Serial.println("DEBUG: clock updated via NTP."); Serial.println("DEBUG: clock updated via NTP.");
#endif #endif
dps["serial"] = serial; api["serial"] = serial;
postData(config, dpsURL, dps); postData(config, apiURL, api);
telemetry["device"] = serial; telemetry["device"] = serial;
// payload["id"] = serverName; // payload["id"] = serverName;

View File

@ -18,7 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.contrib import admin from django.contrib import admin
from dps.models import Device, WhiteList from api.models import Device, WhiteList
@admin.register(Device) @admin.register(Device)

View File

@ -20,5 +20,5 @@
from django.apps import AppConfig from django.apps import AppConfig
class DPSConfig(AppConfig): class ApiConfig(AppConfig):
name = 'dps' name = 'api'

View File

@ -1,6 +1,6 @@
# Generated by Django 3.1.3 on 2021-03-19 08:08 # Generated by Django 3.1.3 on 2021-03-19 08:08
import dps.models import api.models
from django.db import migrations, models from django.db import migrations, models
import uuid import uuid
@ -16,7 +16,7 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='Device', name='Device',
fields=[ fields=[
('serial', models.CharField(max_length=128, unique=True, validators=[dps.models.device_validation])), ('serial', models.CharField(max_length=128, unique=True, validators=[api.models.device_validation])),
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('creation_time', models.DateTimeField(auto_now_add=True)), ('creation_time', models.DateTimeField(auto_now_add=True)),
('updated_time', models.DateTimeField(auto_now=True)), ('updated_time', models.DateTimeField(auto_now=True)),

View File

@ -18,7 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from rest_framework import serializers from rest_framework import serializers
from dps.models import Device, device_validation from api.models import Device, device_validation
class DeviceSerializer(serializers.ModelSerializer): class DeviceSerializer(serializers.ModelSerializer):

View File

@ -18,10 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.test import TestCase, Client from django.test import TestCase, Client
from dps.models import Device, WhiteList from api.models import Device, WhiteList
class DPSTestCase(TestCase): class ApiTestCase(TestCase):
c = Client() c = Client()
def setUp(self): def setUp(self):
@ -29,17 +29,17 @@ class DPSTestCase(TestCase):
Device.objects.create(serial='test1234') Device.objects.create(serial='test1234')
def test_no_whitelist(self): def test_no_whitelist(self):
response = self.c.post('/dps/device/provision/', response = self.c.post('/api/device/subscribe/',
{'serial': 'test12345'}) {'serial': 'test12345'})
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
def test_provision_post(self): def test_subscribe_post(self):
WhiteList.objects.create(serial='test12345') WhiteList.objects.create(serial='test12345')
response = self.c.post('/dps/device/provision/', response = self.c.post('/api/device/subscribe/',
{'serial': 'test12345'}) {'serial': 'test12345'})
self.assertEqual(response.status_code, 201) self.assertEqual(response.status_code, 201)
def test_provision_get(self): def test_subscribe_get(self):
response = self.c.get('/dps/device/list/') response = self.c.get('/api/device/list/')
self.assertEqual( self.assertEqual(
response.json()[0]['serial'], 'test1234') response.json()[0]['serial'], 'test1234')

View File

@ -33,13 +33,13 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.urls import path from django.urls import path
from dps.views import DPS from api.views import APISubscribe
urlpatterns = [ urlpatterns = [
path('device/provision/', path('device/subscribe/',
DPS.as_view({'post': 'create'}), APISubscribe.as_view({'post': 'create'}),
name='device-provision'), name='device-subscribe'),
path('device/list/', path('device/list/',
DPS.as_view({'get': 'list'}), APISubscribe.as_view({'get': 'list'}),
name='device-list'), name='device-list'),
] ]

View File

@ -19,10 +19,10 @@
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from dps.models import Device from api.models import Device
from dps.serializers import DeviceSerializer from api.serializers import DeviceSerializer
class DPS(ModelViewSet): class APISubscribe(ModelViewSet):
queryset = Device.objects.all() queryset = Device.objects.all()
serializer_class = DeviceSerializer serializer_class = DeviceSerializer

View File

@ -1,20 +0,0 @@
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'bite',
'USER': 'bite',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '5432',
}
}
MQTT_BROKER = {
'HOST': 'localhost',
'PORT': '1883',
}
KAFKA_BROKER = {
'HOST': 'localhost',
'PORT': '29092',
}

View File

@ -61,7 +61,7 @@ INSTALLED_APPS = [
# 'health_check.storage', # 'health_check.storage',
'rest_framework', 'rest_framework',
'bite', 'bite',
'dps', 'api',
'telemetry', 'telemetry',
] ]
@ -167,12 +167,11 @@ KAFKA_BROKER = {
'PORT': '9092', 'PORT': '9092',
} }
try: # If no local_settings.py is availble in the current folder let's try to
from bite.local_settings import * # load it from the application root
except ImportError:
pass
try: try:
from bite.production import * from bite.production import *
except ImportError: except ImportError:
# If a local_setting.py does not exist
# settings in this file only will be used
pass pass

View File

@ -37,13 +37,13 @@ from django.contrib import admin
from django.conf import settings from django.conf import settings
from django.urls import include, path from django.urls import include, path
from dps import urls as dps_urls from api import urls as api_urls
from telemetry import urls as telemetry_urls from telemetry import urls as telemetry_urls
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('ht/', include('health_check.urls')), path('ht/', include('health_check.urls')),
path('dps/', include(dps_urls)), path('api/', include(api_urls)),
path('telemetry/', include(telemetry_urls)), path('telemetry/', include(telemetry_urls)),
] ]

View File

@ -31,16 +31,16 @@ from django.conf import settings
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from dps.models import Device from api.models import Device
class Command(BaseCommand): class Command(BaseCommand):
help = "Telemetry dispatcher" help = 'MQTT to DB deamon'
MQTT_HOST = settings.MQTT_BROKER["HOST"] MQTT_HOST = settings.MQTT_BROKER['HOST']
MQTT_PORT = int(settings.MQTT_BROKER["PORT"]) MQTT_PORT = int(settings.MQTT_BROKER['PORT'])
KAFKA_HOST = settings.KAFKA_BROKER["HOST"] KAFKA_HOST = settings.KAFKA_BROKER['HOST']
KAFKA_PORT = int(settings.KAFKA_BROKER["PORT"]) KAFKA_PORT = int(settings.KAFKA_BROKER['PORT'])
producer = None producer = None
@sync_to_async @sync_to_async
@ -52,7 +52,10 @@ class Command(BaseCommand):
@sync_to_async @sync_to_async
def dispatch(self, message): def dispatch(self, message):
self.producer.send("telemetry", {"transport": "mqtt", "body": message}) self.producer.send(
'telemetry', {"transport": 'mqtt',
"body": message}
)
async def mqtt_broker(self): async def mqtt_broker(self):
async with Client(self.MQTT_HOST, port=self.MQTT_PORT) as client: async with Client(self.MQTT_HOST, port=self.MQTT_PORT) as client:
@ -63,13 +66,12 @@ class Command(BaseCommand):
device = await self.get_device(message.topic) device = await self.get_device(message.topic)
if device is not None: if device is not None:
message_body = json.loads( message_body = json.loads(
message.payload.decode("utf-8") message.payload.decode('utf-8'))
)
await self.dispatch(message_body) await self.dispatch(message_body)
else: else:
self.stdout.write( self.stdout.write(
self.style.ERROR("DEBUG: message discarded") self.style.ERROR(
) 'DEBUG: message discarded'))
def handle(self, *args, **options): def handle(self, *args, **options):
client = mqtt.Client() client = mqtt.Client()
@ -79,26 +81,24 @@ class Command(BaseCommand):
break break
except (socket.gaierror, ConnectionRefusedError): except (socket.gaierror, ConnectionRefusedError):
self.stdout.write( self.stdout.write(
self.style.WARNING("WARNING: MQTT broker not available") self.style.WARNING('WARNING: MQTT broker not available'))
)
time.sleep(5) time.sleep(5)
while True: while True:
try: try:
self.producer = KafkaProducer( self.producer = KafkaProducer(
bootstrap_servers="{}:{}".format( bootstrap_servers='{}:{}'.format(
self.KAFKA_HOST, self.KAFKA_PORT self.KAFKA_HOST, self.KAFKA_PORT
), ),
value_serializer=lambda v: json.dumps(v).encode("utf-8"), value_serializer=lambda v: json.dumps(v).encode('utf-8'),
retries=5, retries=5
) )
break break
except NoBrokersAvailable: except NoBrokersAvailable:
self.stdout.write( self.stdout.write(
self.style.WARNING("WARNING: Kafka broker not available") self.style.WARNING('WARNING: Kafka broker not available'))
)
time.sleep(5) time.sleep(5)
self.stdout.write(self.style.SUCCESS("INFO: Brokers subscribed")) self.stdout.write(self.style.SUCCESS('INFO: Brokers subscribed'))
client.disconnect() client.disconnect()
asyncio.run(self.mqtt_broker()) asyncio.run(self.mqtt_broker())

View File

@ -26,15 +26,15 @@ from django.conf import settings
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from dps.models import Device from api.models import Device
from telemetry.models import Telemetry from telemetry.models import Telemetry
class Command(BaseCommand): class Command(BaseCommand):
help = "Telemetry handler" help = 'MQTT to DB deamon'
KAFKA_HOST = settings.KAFKA_BROKER["HOST"] KAFKA_HOST = settings.KAFKA_BROKER['HOST']
KAFKA_PORT = int(settings.KAFKA_BROKER["PORT"]) KAFKA_PORT = int(settings.KAFKA_BROKER['PORT'])
def get_device(self, serial): def get_device(self, serial):
try: try:
@ -47,7 +47,7 @@ class Command(BaseCommand):
transport=transport, transport=transport,
device=self.get_device(message["device"]), device=self.get_device(message["device"]),
clock=message["clock"], clock=message["clock"],
payload=message["payload"], payload=message["payload"]
) )
def handle(self, *args, **options): def handle(self, *args, **options):
@ -55,22 +55,22 @@ class Command(BaseCommand):
try: try:
consumer = KafkaConsumer( consumer = KafkaConsumer(
"telemetry", "telemetry",
bootstrap_servers="{}:{}".format( bootstrap_servers='{}:{}'.format(
self.KAFKA_HOST, self.KAFKA_PORT self.KAFKA_HOST, self.KAFKA_PORT
), ),
group_id="handler", group_id="handler",
value_deserializer=lambda m: json.loads(m.decode("utf8")), value_deserializer=lambda m: json.loads(m.decode('utf8')),
) )
break break
except NoBrokersAvailable: except NoBrokersAvailable:
self.stdout.write( self.stdout.write(
self.style.WARNING("WARNING: Kafka broker not available") self.style.WARNING('WARNING: Kafka broker not available'))
)
time.sleep(5) time.sleep(5)
self.stdout.write(self.style.SUCCESS("INFO: Kafka broker subscribed")) self.stdout.write(self.style.SUCCESS('INFO: Kafka broker subscribed'))
for message in consumer: for message in consumer:
self.store_telemetry( self.store_telemetry(
message.value["transport"], message.value["body"] message.value["transport"],
message.value["body"]
) )
consumer.unsuscribe() consumer.unsuscribe()

View File

@ -11,7 +11,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('dps', '0001_initial'), ('api', '0001_initial'),
] ]
operations = [ operations = [
@ -23,7 +23,7 @@ class Migration(migrations.Migration):
('transport', models.CharField(choices=[('http', 'http'), ('mqtt', 'mqtt')], default='http', max_length=4)), ('transport', models.CharField(choices=[('http', 'http'), ('mqtt', 'mqtt')], default='http', max_length=4)),
('clock', models.IntegerField(null=True, validators=[django.core.validators.MinValueValidator(0)])), ('clock', models.IntegerField(null=True, validators=[django.core.validators.MinValueValidator(0)])),
('payload', models.JSONField(validators=[telemetry.models.telemetry_validation])), ('payload', models.JSONField(validators=[telemetry.models.telemetry_validation])),
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dps.device')), ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.device')),
], ],
options={ options={
'verbose_name_plural': 'Telemetry', 'verbose_name_plural': 'Telemetry',

View File

@ -21,7 +21,7 @@ from django.db import models
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from dps.models import Device from api.models import Device
def telemetry_validation(value): def telemetry_validation(value):

View File

@ -18,7 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from rest_framework import serializers from rest_framework import serializers
from dps.models import Device from api.models import Device
from telemetry.models import Telemetry from telemetry.models import Telemetry

View File

@ -19,7 +19,7 @@
import json import json
from django.test import TestCase, Client from django.test import TestCase, Client
from dps.models import Device, WhiteList from api.models import Device, WhiteList
class ApiTestCase(TestCase): class ApiTestCase(TestCase):

View File

@ -37,11 +37,8 @@ services:
- "${CUSTOM_DOCKER_IP:-0.0.0.0}:8000:8000" - "${CUSTOM_DOCKER_IP:-0.0.0.0}:8000:8000"
kafka: kafka:
environment:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
ports: ports:
- "${CUSTOM_DOCKER_IP:-0.0.0.0}:29092:29092" - "${CUSTOM_DOCKER_IP:-0.0.0.0}:9092:9092"
data-migration: data-migration:
volumes: volumes:

View File

@ -43,7 +43,7 @@ services:
timescale: timescale:
<<: *service_default <<: *service_default
image: timescale/timescaledb:latest-pg15 image: timescale/timescaledb:latest-pg12
environment: environment:
POSTGRES_USER: "bite" POSTGRES_USER: "bite"
POSTGRES_PASSWORD: "password" POSTGRES_PASSWORD: "password"
@ -69,6 +69,8 @@ services:
environment: environment:
ZOOKEEPER_CLIENT_PORT: 2181 ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000 ZOOKEEPER_TICK_TIME: 2000
ports:
- 22181:2181
kafka: kafka:
image: confluentinc/cp-kafka:latest image: confluentinc/cp-kafka:latest
@ -79,8 +81,8 @@ services:
environment: environment:
KAFKA_BROKER_ID: 1 KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
@ -97,6 +99,7 @@ services:
- staticdata:/srv/appdata/bite/static - staticdata:/srv/appdata/bite/static
- ./ingress/nginx.conf:/etc/nginx/nginx.conf - ./ingress/nginx.conf:/etc/nginx/nginx.conf
bite: bite:
<<: *service_default <<: *service_default
build: build:

View File

@ -29,7 +29,7 @@ import argparse
from time import sleep from time import sleep
import paho.mqtt.publish as publish import paho.mqtt.publish as publish
DEBUG = bool(os.environ.get("IOT_DEBUG", False)) DEBUG = bool(os.environ.get('IOT_DEBUG', False))
http = urllib3.PoolManager() http = urllib3.PoolManager()
@ -39,16 +39,15 @@ def post_json(endpoint, url, data):
if DEBUG: if DEBUG:
print(json_data) print(json_data)
encoded_data = json_data.encode("utf8") encoded_data = json_data.encode('utf8')
while True: while True:
try: try:
r = http.request( r = http.request(
"POST", 'POST',
endpoint + url, endpoint + url,
body=encoded_data, body=encoded_data,
headers={"content-type": "application/json"}, headers={'content-type': 'application/json'})
)
return r return r
except urllib3.exceptions.MaxRetryError: except urllib3.exceptions.MaxRetryError:
pass pass
@ -58,89 +57,74 @@ def post_json(endpoint, url, data):
def publish_json(transport, endpoint, data): def publish_json(transport, endpoint, data):
json_data = json.dumps(data) json_data = json.dumps(data)
serial = data["device"] serial = data['device']
if DEBUG: if DEBUG:
print(json_data) print(json_data)
encoded_data = json_data.encode("utf8") encoded_data = json_data.encode('utf8')
publish.single( publish.single(
topic=serial, topic=serial,
payload=encoded_data, payload=encoded_data,
hostname=endpoint.split(":")[0], hostname=endpoint.split(':')[0],
port=int(endpoint.split(":")[1]), port=int(endpoint.split(':')[1]),
client_id=serial, client_id=serial,
transport=("websockets" if transport == "ws" else "tcp"), transport=('websockets' if transport == 'ws' else 'tcp'),
# auth=auth FIXME # auth=auth FIXME
) )
def main(): def main():
parser = argparse.ArgumentParser(description="IoT simulator oprions") parser = argparse.ArgumentParser(
description='IoT simulator oprions')
parser.add_argument( parser.add_argument('-e', '--endpoint',
"-e", default=os.environ.get('IOT_HTTP',
"--endpoint", 'http://127.0.0.1:8000'),
default=os.environ.get("IOT_HTTP", "http://127.0.0.1:8000"), help='IoT HTTP endpoint')
help="IoT HTTP endpoint", parser.add_argument('-m', '--mqtt',
) default=os.environ.get('IOT_MQTT',
parser.add_argument( '127.0.0.1:1883'),
"-m", help='IoT MQTT endpoint')
"--mqtt", parser.add_argument('-t', '--transport',
default=os.environ.get("IOT_MQTT", "127.0.0.1:1883"), choices=['mqtt', 'ws', 'http'],
help="IoT MQTT endpoint", default=os.environ.get('IOT_TL', 'http'),
) help='IoT transport layer')
parser.add_argument( parser.add_argument('-s', '--serial',
"-t", default=os.environ.get('IOT_SERIAL'),
"--transport", help='IoT device serial number')
choices=["mqtt", "ws", "http"], parser.add_argument('-d', '--delay', metavar='s', type=float,
default=os.environ.get("IOT_TL", "http"), default=os.environ.get('IOT_DELAY', 10),
help="IoT transport layer", help='Delay between requests')
)
parser.add_argument(
"-s",
"--serial",
default=os.environ.get("IOT_SERIAL"),
help="IoT device serial number",
)
parser.add_argument(
"-d",
"--delay",
metavar="s",
type=float,
default=os.environ.get("IOT_DELAY", 10),
help="Delay between requests",
)
args = parser.parse_args() args = parser.parse_args()
dps = "/dps/device/provision/" subscribe = '/api/device/subscribe/'
telemetry = "/telemetry/" telemetry = '/telemetry/'
if args.serial is None: if args.serial is None:
args.serial = "".join( args.serial = ''.join(
random.choices(string.ascii_lowercase + string.digits, k=8) random.choices(string.ascii_lowercase + string.digits, k=8))
)
data = {"serial": args.serial} data = {'serial': args.serial}
post_json(args.endpoint, dps, data) post_json(args.endpoint, subscribe, data)
while True: while True:
data = { data = {
"device": args.serial, 'device': args.serial,
"clock": int(datetime.datetime.now().timestamp()), 'clock': int(datetime.datetime.now().timestamp()),
} }
payload = { payload = {
"id": "device_simulator", 'id': 'device_simulator',
"light": random.randint(300, 500), 'light': random.randint(300, 500),
"temperature": {"celsius": round(random.uniform(20, 28), 1)}, 'temperature': {
'celsius': round(random.uniform(20, 28), 1)}
} }
if args.transport == "http": if args.transport == 'http':
post_json(args.endpoint, telemetry, {**data, "payload": payload}) post_json(args.endpoint, telemetry, {**data, 'payload': payload})
elif args.transport in ("mqtt", "ws"): elif args.transport in ('mqtt', 'ws'):
publish_json( publish_json(
args.transport, args.mqtt, {**data, "payload": payload} args.transport, args.mqtt, {**data, 'payload': payload})
)
else: else:
raise NotImplementedError raise NotImplementedError
sleep(args.delay) sleep(args.delay)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -55,13 +55,13 @@ struct netConfig {
} config; } config;
char* serial; char* serial;
const String dpsURL = "/dps/device/subscribe/"; const String apiURL = "/api/device/subscribe/";
const String telemetryURL = "/telemetry/"; const String telemetryURL = "/telemetry/";
void setup(void) { void setup(void) {
Serial.begin(115200); Serial.begin(115200);
StaticJsonDocument<64> dps; StaticJsonDocument<64> api;
preferences.begin("iot"); preferences.begin("iot");
// Get the serial number from flash // Get the serial number from flash
@ -117,8 +117,8 @@ void setup(void) {
Serial.println("DEBUG: clock updated via NTP."); Serial.println("DEBUG: clock updated via NTP.");
#endif #endif
dps["serial"] = serial; api["serial"] = serial;
postData(config, dpsURL, dps); postData(config, apiURL, api);
telemetry["device"] = serial; telemetry["device"] = serial;
// payload["id"] = serverName; // payload["id"] = serverName;