Skip to content

Commit bf47696

Browse files
committed
Finish firmware
1 parent 4578ff8 commit bf47696

File tree

8 files changed

+154
-134
lines changed

8 files changed

+154
-134
lines changed

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.stl filter=lfs diff=lfs merge=lfs -text
2+
*.FCStd filter=lfs diff=lfs merge=lfs -text
3+
*.png filter=lfs diff=lfs merge=lfs -text

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
.vscode/c_cpp_properties.json
44
.vscode/launch.json
55
.vscode/ipch
6-
src/secret.h
6+
src/secret.h

include/README

Lines changed: 0 additions & 39 deletions
This file was deleted.

lib/README

Lines changed: 0 additions & 46 deletions
This file was deleted.

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
platform = atmelsam
1313
board = nano_33_iot
1414
framework = arduino
15+
src_filter = +<*> -<.git> -<.vscode> -<src/secret_example.h>
1516
lib_deps =
1617
arduino-libraries/WiFiNINA@^1.8.13
1718
bblanchon/ArduinoJson@^6.18.5
18-

src/main.cpp

Lines changed: 146 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,63 @@
1111

1212
WiFiServer server(80);
1313

14+
char MAC_ADDRESS[32];
15+
16+
struct Color {
17+
Color() = default;
18+
Color(float r, float g, float b, float w) : r(r), g(g), b(b), w(w) {}
19+
20+
bool operator==(const Color& other) const {
21+
return r == other.r && g == other.g && b == other.b && w == other.w;
22+
}
23+
bool operator!=(const Color& other) const { return !operator==(other); }
24+
25+
Color operator+(const Color& other) const {
26+
return Color(r + other.r, g + other.g, b + other.b, w + other.w);
27+
}
28+
Color operator-(const Color& other) const {
29+
return Color(r - other.r, g - other.g, b - other.b, w - other.w);
30+
}
31+
Color operator*(const Color& other) const {
32+
return Color(r * other.r, g * other.g, b * other.b, w * other.w);
33+
}
34+
Color operator/(const Color& other) const {
35+
return Color(r / other.r, g / other.g, b / other.b, w / other.w);
36+
}
37+
38+
Color operator+(float val) const {
39+
return Color(r + val, g + val, b + val, w + val);
40+
}
41+
Color operator-(float val) const {
42+
return Color(r - val, g - val, b - val, w - val);
43+
}
44+
Color operator*(float val) const {
45+
return Color(r * val, g * val, b * val, w * val);
46+
}
47+
Color operator/(float val) const {
48+
return Color(r / val, g / val, b / val, w / val);
49+
}
50+
51+
float r = 0, g = 0, b = 0, w = 0;
52+
53+
void apply() {
54+
auto convert = [=](float val) {
55+
return constrain(round(val * 4095.f), 0, 4095);
56+
};
57+
analogWrite(RED, convert(r));
58+
analogWrite(GREEN, convert(g));
59+
analogWrite(BLUE, convert(b));
60+
analogWrite(WHITE, convert(w));
61+
}
62+
};
63+
64+
struct State {
65+
bool isOn = false;
66+
Color target;
67+
Color current;
68+
unsigned long transitionTime = 0;
69+
} state;
70+
1471
void setup() {
1572
// check for the WiFi module:
1673
if (WiFi.status() == WL_NO_MODULE) {
@@ -43,87 +100,121 @@ void setup() {
43100
Serial.print("IP Address: ");
44101
Serial.println(ip);
45102

103+
byte mac[6];
104+
WiFi.macAddress(mac);
105+
sprintf(MAC_ADDRESS, "%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
106+
Serial.print("MAC: ");
107+
Serial.println(MAC_ADDRESS);
108+
46109
server.begin();
47110

48111
pinMode(LED_BUILTIN, OUTPUT);
49112
digitalWrite(LED_BUILTIN, HIGH);
50-
}
51-
52-
struct Color {
53-
uint8_t r = 0, g = 0, b = 0, w = 0;
54113

55-
void apply() {
56-
analogWrite(RED, r);
57-
analogWrite(GREEN, g);
58-
analogWrite(BLUE, b);
59-
analogWrite(WHITE, w);
60-
}
61-
};
62-
63-
Color current;
114+
analogWriteResolution(12);
115+
}
64116

65117
enum class HttpMethod {
66118
GET,
67119
POST,
68120
UNKNOWN
69121
};
70122

123+
const unsigned int LOOP_TIME = 10; // ms
124+
125+
const Color off(0, 0, 0, 0);
126+
71127
void loop() {
128+
if (WiFi.status() != WL_CONNECTED) {
129+
Serial.println("WiFi lost, reseting arduino in 10 seconds");
130+
delay(10000);
131+
NVIC_SystemReset();
132+
}
133+
72134
WiFiClient client = server.available();
73135

74-
if (client) {
75-
Serial.println("Client available");
136+
static unsigned int prev = 0;
137+
const unsigned long time = millis();
138+
const unsigned int diff = time - prev;
76139

140+
if (client) {
77141
size_t lineNo = 0;
78142
HttpMethod method = HttpMethod::UNKNOWN;
143+
char route[20];
79144

80145
// Parse Headers
81146
while (client.available()) {
82147
String line = client.readStringUntil('\r');
83148
client.read(); // Discard \n
84-
Serial.println(line);
85149

86150
if (lineNo == 0) {
87151
if (line.startsWith("GET")) {
88152
method = HttpMethod::GET;
89153
} else if (line.startsWith("POST")) {
90154
method = HttpMethod::POST;
91155
}
156+
157+
const char* routeBegin = strchr(line.c_str(), ' ') + 1;
158+
size_t i = 0;
159+
while (i < sizeof(route) && routeBegin[i] != '\0' && routeBegin[i] != ' ') {
160+
route[i] = routeBegin[i];
161+
i++;
162+
}
163+
route[i] = '\0';
92164
}
93165

94166
if (line.length() == 0) {
95167
// End of headers
96168
break;
97169
}
170+
171+
lineNo++;
98172
}
99173

100-
if (method == HttpMethod::GET) {
101-
DynamicJsonDocument doc(1024);
174+
if (method == HttpMethod::POST && strcmp(route, "/command") == 0) {
175+
StaticJsonDocument<1024> req;
176+
StaticJsonDocument<1024> res;
177+
deserializeJson(req, client);
102178

103-
doc["r"] = current.r;
104-
doc["g"] = current.g;
105-
doc["b"] = current.b;
106-
doc["w"] = current.w;
179+
const char* method = req["method"];
180+
auto param = req["param"];
107181

108-
client.println("HTTP/1.1 200 OK");
109-
client.println("Content-Type: application/json");
110-
client.println("Connection: close");
111-
client.println();
112-
serializeJson(doc, client);
113-
} else if (method == HttpMethod::POST) {
114-
DynamicJsonDocument doc(1024);
115-
deserializeJson(doc, client);
116-
117-
current.r = doc["r"];
118-
current.g = doc["g"];
119-
current.b = doc["b"];
120-
current.w = doc["w"];
182+
if (strcmp(method, "set_rgbw") == 0) {
183+
if (param["time"]) {
184+
state.transitionTime = param["time"].as<unsigned long>();
185+
} else {
186+
state.transitionTime = 1000;
187+
}
121188

122-
current.apply();
189+
state.target.r = constrain(param["r"], 0.f, 1.f);
190+
state.target.g = constrain(param["g"], 0.f, 1.f);
191+
state.target.b = constrain(param["b"], 0.f, 1.f);
192+
state.target.w = constrain(param["w"], 0.f, 1.f);
193+
} else if (strcmp(method, "set_power") == 0) {
194+
state.isOn = param["value"];
195+
if (!state.isOn || state.transitionTime < 1000) {
196+
state.transitionTime = 1000;
197+
}
198+
} else if (strcmp(method, "get_status") == 0) {
199+
res["power"] = state.isOn;
200+
res["r"] = (float)state.target.r;
201+
res["g"] = (float)state.target.g;
202+
res["b"] = (float)state.target.b;
203+
res["w"] = (float)state.target.w;
204+
} else if (strcmp(method, "get_info") == 0) {
205+
res["mac"] = MAC_ADDRESS;
206+
} else {
207+
client.println("HTTP/1.1 404 Not Found");
208+
client.println("Connection: close");
209+
client.println();
210+
}
123211

124212
client.println("HTTP/1.1 200 OK");
125213
client.println("Connection: close");
126214
client.println();
215+
if (!res.isNull()) {
216+
serializeJson(res, client);
217+
}
127218
} else {
128219
client.println("HTTP/1.1 404 Not Found");
129220
client.println("Connection: close");
@@ -132,4 +223,23 @@ void loop() {
132223

133224
client.stop();
134225
}
226+
227+
const Color target = state.isOn ? state.target : off;
228+
229+
if (state.transitionTime > 0) {
230+
float ratio = (float)LOOP_TIME / (float)state.transitionTime;
231+
ratio = min(max(ratio, 0.f), 1.0f);
232+
state.current = state.current * (1.f - ratio) + target * ratio;
233+
state.current.apply();
234+
235+
if (state.transitionTime > diff) {
236+
state.transitionTime -= diff;
237+
} else {
238+
state.transitionTime = 0;
239+
}
240+
}
241+
242+
prev = time;
243+
244+
delay(LOOP_TIME);
135245
}

src/secret_example.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Rename this file to secret.h
2+
#define SECRET_SSID <insert-wifi-SSID-here>
3+
#define SECRET_PASS <insert-wifi-PASSWORD-here>

test/README

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)