summaryrefslogtreecommitdiffstats
path: root/bs_button/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'bs_button/src/main.cpp')
-rw-r--r--bs_button/src/main.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/bs_button/src/main.cpp b/bs_button/src/main.cpp
new file mode 100644
index 0000000..290284c
--- /dev/null
+++ b/bs_button/src/main.cpp
@@ -0,0 +1,260 @@
1#include <Arduino.h>
2#include <ESP8266WiFi.h>
3
4#include <DNSServer.h>
5#include <ESP8266WebServer.h>
6#include <WiFiManager.h>
7
8#include <PubSubClient.h>
9#include <Bounce2.h>
10
11#include <ESP8266httpUpdate.h>
12
13#include <AudioGeneratorMP3.h>
14#include <AudioFileSourcePROGMEM.h>
15#include <AudioOutputI2SNoDAC.h>
16
17#include "ledcontrol.h"
18
19#define PIN_BUTTON D2
20#define PIN_LED D1
21
22#define LED_ON HIGH
23#define LED_OFF LOW
24
25#include "secrets.h"
26
27#define MQTT_BROKER "maqiatto.com"
28#define MQTT_BROKER_PORT 1883
29//#define MQTT_USERNAME ""
30//#define MQTT_PASSWORD ""
31#define MQTT_BASE MQTT_USERNAME "/bsbutton"
32
33// fw update
34// - increment number + build
35// - scp .pio/build/$ENV/firmware.bin manuel@mausz.at:public_html/coding/.firmware/bsbutton.bin
36// - reboot device or send "fwupdate" to mqtt_topic_cmd
37// - fw update state go to mqtt_topic_state
38#define FIRMWARE_VERSION 4
39//#define FIRMWARE_URL ""
40
41// tracks
42// - ffmpeg -i input.mp3 -vn -ar 44100 -ac 1 -b:a 32k output.mp3
43// - xxd -i output.mp3 mytrack.h
44// - modify mytrack.h: const unsigned char xxx_mp3[] PROGMEM = ...
45// - add variable to arrays
46#include "alert.h"
47#include "manuel.h"
48#include "rickroll.h"
49#include "llama.h"
50#include "kit.h"
51#include "starwars.h"
52const unsigned char *tracks[] = {
53 alert_mp3,
54 manuel_mp3,
55 rickroll_mp3,
56 llama_mp3,
57 kit_mp3,
58 starwars_mp3
59};
60const unsigned int tracks_len[] = {
61 sizeof(alert_mp3),
62 sizeof(manuel_mp3),
63 sizeof(rickroll_mp3),
64 sizeof(llama_mp3),
65 sizeof(kit_mp3),
66 sizeof(starwars_mp3)
67};
68long track_count = sizeof(tracks) / sizeof(unsigned char*);
69
70#define _STR(s) #s
71#define STR(s) _STR(s)
72const String mqtt_clientId = "BSButton-" + String(ESP.getChipId())
73 + "/v" + STR(FIRMWARE_VERSION);
74const char* mqtt_topic_ping = MQTT_BASE "/ping";
75const char* mqtt_topic_cmd = MQTT_BASE "/command";
76const String mqtt_topic_state = String(MQTT_BASE) + "/" + String(ESP.getChipId());
77
78class LedControl;
79bool mqttLoop();
80void mqttCallback(char *topic, byte *payload, unsigned int length);
81void blinkLed(const unsigned long interval);
82void checkFirmwareUpdate();
83
84WiFiClient wifi_client;
85PubSubClient mqtt(wifi_client);
86Bounce button = Bounce();
87LedControl led(PIN_LED, LED_ON);
88
89AudioGeneratorMP3 *mp3;
90AudioFileSourcePROGMEM *file;
91AudioOutputI2SNoDAC *out;
92
93void setup()
94{
95 Serial.begin(115200);
96 randomSeed(analogRead(PIN_LED));
97
98 pinMode(PIN_BUTTON, INPUT_PULLUP);
99 button.attach(PIN_BUTTON);
100 button.interval(25);
101
102 led.on();
103
104 WiFiManager wifiManager;
105 wifiManager.setConfigPortalTimeout(600);
106 Serial.printf_P(PSTR("Setting up WiFi\n"));
107 if (!wifiManager.autoConnect("Bullshit")) {
108 Serial.printf_P(PSTR("Failed to connect and hit timeout\n"));
109 delay(5000);
110 ESP.restart();
111 }
112
113 yield();
114 checkFirmwareUpdate();
115 yield();
116
117 mqtt.setServer(MQTT_BROKER, MQTT_BROKER_PORT);
118 mqtt.setCallback(mqttCallback);
119
120 mp3 = new AudioGeneratorMP3();
121 file = new AudioFileSourcePROGMEM();
122 out = new AudioOutputI2SNoDAC();
123 out->SetGain(3.0); //NOTE >=4.0 does not work?
124
125 pinMode(LED_BUILTIN, OUTPUT);
126 digitalWrite(LED_BUILTIN, HIGH);
127}
128
129void loop()
130{
131 if (mp3->isRunning()) {
132 led.blink(200);
133 if (!mp3->loop())
134 {
135 mp3->stop();
136 led.off();
137 }
138 }
139 else
140 {
141 // turn off the blinking led
142 //if (ledState == LED_ON)
143 // blinkLed();
144
145 if (!mqttLoop())
146 {
147 delay(5000);
148 return;
149 }
150
151 // prohibit triggering the button multiple times
152 static unsigned long button_lock_millis = 1000;
153 static unsigned long button_pressed_millis = 0;
154 button.update();
155 if (button.rose() && millis() - button_pressed_millis >= button_lock_millis)
156 {
157 const long track = random(track_count);
158 Serial.printf_P(PSTR("Button pressed. It's track #%ld\n"), track);
159 String tmp = "play" + String(track);
160 mqtt.publish(mqtt_topic_cmd, tmp.c_str());
161
162 button_pressed_millis = millis();
163 }
164 }
165}
166
167bool mqttLoop()
168{
169 if (!mqtt.connected())
170 {
171 led.on();
172 Serial.printf_P(PSTR("Connecting to MQTT\n"));
173 if (!mqtt.connect(mqtt_clientId.c_str(), MQTT_USERNAME, MQTT_PASSWORD))
174 return false;
175
176 Serial.printf_P(PSTR("MQTT connected\n"));
177 led.off();
178
179 mqtt.publish(mqtt_topic_ping, mqtt_clientId.c_str());
180 mqtt.subscribe(mqtt_topic_ping);
181 mqtt.subscribe(mqtt_topic_cmd);
182 }
183
184 yield();
185 mqtt.loop();
186 return true;
187}
188
189void mqttCallback(char *topic, byte *payload, unsigned int length)
190{
191 char c_payload[length + 1];
192 memcpy(c_payload, payload, length);
193 c_payload[length] = '\0';
194
195 if (!strcmp(topic, mqtt_topic_ping))
196 {
197 if (!strcmp(c_payload, "ping"))
198 mqtt.publish(mqtt_topic_ping, mqtt_clientId.c_str());
199 return;
200 }
201 else if (!strcmp(topic, mqtt_topic_cmd))
202 {
203 if (!strncmp(c_payload, "play", 4))
204 {
205 long track = atoi(c_payload + 4);
206 if (track >= track_count)
207 return;
208
209 Serial.printf_P(PSTR("Playing track #%ld\n"), track);
210 file->open(tracks[track], tracks_len[track]);
211 mp3->begin(file, out);
212 return;
213 }
214 else if (!strcmp(c_payload, "fwupdate"))
215 {
216 checkFirmwareUpdate();
217 return;
218 }
219 else if (!strcmp(c_payload, "reset"))
220 {
221 Serial.printf_P(PSTR("Resetting\n"));
222 ESP.reset();
223 return;
224 }
225 }
226
227 Serial.printf_P(PSTR("Unhandled MQTT message: [%s] %s\n"), topic, c_payload);
228}
229
230void checkFirmwareUpdate()
231{
232 BearSSL::WiFiClientSecure update_client;
233 update_client.setInsecure();
234
235 mqtt.publish(mqtt_topic_state.c_str(), "fwupdate running");
236 ESPhttpUpdate.setLedPin(PIN_LED, LED_ON);
237 ESPhttpUpdate.rebootOnUpdate(true);
238 t_httpUpdate_return ret = ESPhttpUpdate.update(update_client, FIRMWARE_URL, STR(FIRMWARE_VERSION));
239 switch(ret)
240 {
241 case HTTP_UPDATE_FAILED:
242 {
243 Serial.printf_P(PSTR("HTTP_UPDATE_FAILED Error (%d): %s\n"),
244 ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
245 String tmp = String("fwupdate error: ") + ESPhttpUpdate.getLastErrorString();
246 mqtt.publish(mqtt_topic_state.c_str(), tmp.c_str());
247 }
248 break;
249
250 case HTTP_UPDATE_NO_UPDATES:
251 Serial.printf_P(PSTR("HTTP_UPDATE_NO_UPDATES\n"));
252 mqtt.publish(mqtt_topic_state.c_str(), "fwupdate noupdates");
253 break;
254
255 case HTTP_UPDATE_OK:
256 Serial.printf_P(PSTR("HTTP_UPDATE_OK\n"));
257 mqtt.publish(mqtt_topic_state.c_str(), "fwupdate ok");
258 break;
259 }
260}