Skip to content

Commit b8fe74d

Browse files
authored
Config API and Dash (#14)
1 parent 8fc4a21 commit b8fe74d

File tree

11 files changed

+202
-14
lines changed

11 files changed

+202
-14
lines changed

dash/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"react": "^18.3.1",
44
"react-dom": "^18.3.1",
55
"antd": "^5.23.2",
6+
"axios": "^1.8.2",
67
"@babel/core": "^7.24.9",
78
"@babel/preset-env": "^7.25.0",
89
"@babel/preset-react": "^7.24.7",

dash/src/App.js

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { Layout, Menu } from 'antd';
33
import { InfoCircleOutlined, EditOutlined } from '@ant-design/icons';
4+
import Status from './Status';
5+
import Config from './Config';
46

57
const { Content, Sider } = Layout;
68

@@ -18,13 +20,29 @@ const items = [
1820
]
1921

2022
const App = () => {
23+
const [selectedKey, setSelectedKey] = useState("status");
24+
25+
const renderContent = () => {
26+
switch (selectedKey) {
27+
case "status":
28+
return <Status />;
29+
case "config":
30+
return <Config />;
31+
default:
32+
return null;
33+
}
34+
};
35+
2136
return (
2237
<Layout>
2338
<Sider>
24-
<Menu theme="dark" items={items} defaultSelectedKeys={ [ "status" ] }/>
39+
<Menu theme="dark"
40+
items={items}
41+
defaultSelectedKeys={ [ "status" ] }
42+
onClick={(e) => setSelectedKey(e.key)} />
2543
</Sider>
2644
<Content>
27-
TBD
45+
{renderContent()}
2846
</Content>
2947
</Layout>
3048
);

dash/src/Config.js

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { Form, Input, Button, message } from 'antd';
3+
import axios from 'axios';
4+
5+
const API_ENDPOINT = '/api/config';
6+
7+
const Config = () => {
8+
const [form] = Form.useForm();
9+
const [loading, setLoading] = useState(false);
10+
11+
useEffect(() => {
12+
const getCurrentValues = async () => {
13+
try {
14+
setLoading(true);
15+
const { data } = await axios.get(API_ENDPOINT);
16+
form.setFieldsValue({
17+
"wifi_ssid": data["wifi"]["ssid"],
18+
"wifi_password": data["wifi"]["password"],
19+
"dri_ua_id": data["dri"]["ua_id"],
20+
"dri_ua_desc": data["dri"]["ua_desc"],
21+
"dri_op_id": data["dri"]["op_id"]
22+
});
23+
} catch (error) {
24+
message.error("Could not get current values.");
25+
} finally {
26+
setLoading(false);
27+
}
28+
};
29+
getCurrentValues();
30+
}, [form]);
31+
32+
const onFinish = async (data) => {
33+
try {
34+
setLoading(true);
35+
await axios.post(API_ENDPOINT, {
36+
"wifi": {
37+
"ssid": data["wifi_ssid"],
38+
"password": data["wifi_password"]
39+
},
40+
"dri": {
41+
"ua_id": data["dri_ua_id"],
42+
"ua_desc": data["dri_ua_desc"],
43+
"op_id": data["dri_op_id"]
44+
}
45+
});
46+
message.success("Config saved.");
47+
} catch (error) {
48+
message.error("Config failed to save.");
49+
} finally {
50+
setLoading(false);
51+
}
52+
};
53+
54+
return (
55+
<Form
56+
form={form}
57+
layout="vertical"
58+
onFinish={onFinish}
59+
>
60+
<Form.Item
61+
label="WiFi SSID"
62+
name="wifi_ssid"
63+
rules={[
64+
{ required: true, message: "WiFi SSID must be set." },
65+
]}>
66+
<Input maxLength="32" showCount="true" />
67+
</Form.Item>
68+
69+
<Form.Item
70+
label="WiFi Password"
71+
name="wifi_password"
72+
rules={[
73+
{ required: false },
74+
{ min: 8, message: "WiFi Password must be at least 8 characters long." },
75+
]}
76+
>
77+
<Input.Password maxLength="64" showCount="true" />
78+
</Form.Item>
79+
80+
<Form.Item
81+
label="Unmanned Aircraft ID"
82+
name="dri_ua_id"
83+
rules={[
84+
{ required: true, message: "Unmanned Aircraft ID must be set." },
85+
]}
86+
>
87+
<Input maxLength="20" showCount="true" />
88+
</Form.Item>
89+
90+
<Form.Item
91+
label="Unmanned Aircraft Description"
92+
name="dri_ua_desc"
93+
rules={[
94+
{ required: false },
95+
]}
96+
>
97+
<Input maxLength="23" showCount="true" />
98+
</Form.Item>
99+
100+
<Form.Item
101+
label="Operator ID"
102+
name="dri_op_id"
103+
rules={[
104+
{ required: true, message: "Operator ID must be set." },
105+
]}
106+
>
107+
<Input maxLength="20" showCount="true" />
108+
</Form.Item>
109+
110+
<Form.Item>
111+
<Button type="primary" htmlType="submit" loading={loading}>Save</Button>
112+
</Form.Item>
113+
</Form>
114+
);
115+
};
116+
117+
export default Config;

dash/src/Status.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const Status = () => {
2+
return "Status";
3+
};
4+
5+
export default Status;

platformio.ini

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ lib_deps =
66
mathieucarbou/[email protected]
77
ipdotsetaf/ESPAsyncHTTPUpdateServer@^2.0.0
88
okalachev/MAVLink@^2.0.11
9+
bblanchon/ArduinoJson@^7.3.0
910
build_flags = -Wno-address-of-packed-member
1011

1112
[env:esp32_c3_devkit]

src/config.cpp

+35-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <Preferences.h>
2+
#include <ArduinoJson.h>
23
#include "utils.h"
34

45
#include "config.h"
@@ -26,6 +27,37 @@ void config_init() {
2627
prefs.putString(PREFS_DRI_OP_ID, "");
2728
}
2829

30+
String config_get() {
31+
JsonDocument doc;
32+
doc["wifi"]["ssid"] = config_wifi_ssid();
33+
doc["wifi"]["password"] = config_wifi_password();
34+
doc["dri"]["ua_id"] = config_dri_ua_id();
35+
doc["dri"]["ua_desc"] = config_dri_ua_desc();
36+
doc["dri"]["op_id"] = config_dri_op_id();
37+
String buf;
38+
serializeJson(doc, buf);
39+
return buf;
40+
}
41+
42+
void config_save(String data) {
43+
JsonDocument doc;
44+
DeserializationError err = deserializeJson(doc, data);
45+
if (err) {
46+
Serial.println("JSON Error");
47+
return;
48+
}
49+
String wifi_ssid = doc["wifi"]["ssid"];
50+
prefs.putString(PREFS_WIFI_SSID, wifi_ssid);
51+
String wifi_password = doc["wifi"]["password"];
52+
prefs.putString(PREFS_WIFI_PASSWORD, wifi_password);
53+
String dri_ua_id = doc["dri"]["ua_id"];
54+
prefs.putString(PREFS_DRI_UA_ID, dri_ua_id);
55+
String dri_ua_desc = doc["dri"]["ua_desc"];
56+
prefs.putString(PREFS_DRI_UA_DESC, dri_ua_desc);
57+
String dri_op_id = doc["dri"]["op_id"];
58+
prefs.putString(PREFS_DRI_OP_ID, dri_op_id);
59+
}
60+
2961
String config_wifi_ssid() {
3062
return prefs.getString(PREFS_WIFI_SSID);
3163
}
@@ -34,14 +66,14 @@ String config_wifi_password() {
3466
return prefs.getString(PREFS_WIFI_PASSWORD);
3567
}
3668

37-
String dri_ua_id() {
69+
String config_dri_ua_id() {
3870
return prefs.getString(PREFS_DRI_UA_ID);
3971
}
4072

41-
String dri_ua_desc() {
73+
String config_dri_ua_desc() {
4274
return prefs.getString(PREFS_DRI_UA_DESC);
4375
}
4476

45-
String dri_op_id() {
77+
String config_dri_op_id() {
4678
return prefs.getString(PREFS_DRI_OP_ID);
4779
}

src/config.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
void config_init();
2+
String config_get();
3+
void config_save(String data);
24
String config_wifi_ssid();
35
String config_wifi_password();
4-
String dri_ua_id();
5-
String dri_ua_desc();
6-
String dri_op_id();
6+
String config_dri_ua_id();
7+
String config_dri_ua_desc();
8+
String config_dri_op_id();

src/dash.cpp

+1-1
Large diffs are not rendered by default.

src/dash.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#include <Arduino.h>
22

3-
extern const uint8_t DASH[130101];
3+
extern const uint8_t DASH[192737];

src/dri.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ void ble_transmit(ODID_Message_encoded encoded) {
3333
void dri_init(ODID_UAS_Data *data) {
3434
odid_initUasData(data);
3535

36-
String ua_id = dri_ua_id();
36+
String ua_id = config_dri_ua_id();
3737
if (ua_id != "" && ua_id.length() <= ODID_ID_SIZE) {
3838
data->BasicID[0].IDType = ODID_IDTYPE_SERIAL_NUMBER;
3939
strncpy(data->BasicID[0].UASID, ua_id.c_str(), ODID_ID_SIZE);
4040
}
4141

42-
String op_id = dri_op_id();
42+
String op_id = config_dri_op_id();
4343
if (op_id != "" && op_id.length() <= ODID_ID_SIZE) {
4444
data->OperatorID.OperatorIdType = ODID_OPERATOR_ID;
4545
strncpy(data->OperatorID.OperatorId, op_id.c_str(), ODID_ID_SIZE);
4646
}
4747

48-
String ua_desc = dri_ua_desc();
48+
String ua_desc = config_dri_ua_desc();
4949
if (ua_desc != "" && ua_desc.length() <= ODID_STR_SIZE) {
5050
data->SelfID.DescType = ODID_DESC_TYPE_TEXT;
5151
strncpy(data->SelfID.Desc, ua_desc.c_str(), ODID_STR_SIZE);

src/main.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ void setup() {
4242
response->addHeader("Content-Encoding", "gzip");
4343
request->send(response);
4444
});
45+
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request) {
46+
AsyncWebServerResponse *response = request->beginResponse(200, "application/json", config_get());
47+
request->send(response);
48+
});
49+
server.on("/api/config", HTTP_POST, [](AsyncWebServerRequest *request){
50+
request->send(400);
51+
}, NULL, [](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
52+
config_save((char *)data);
53+
request->send(200);
54+
delay(100);
55+
ESP.restart();
56+
});
4557

4658
mavlink_init(&mavlink_state);
4759

0 commit comments

Comments
 (0)