diff options
| author | manuel <manuel@mausz.at> | 2020-02-04 23:33:05 +0100 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2020-02-04 23:33:05 +0100 |
| commit | 95e5f22a558beeaac8895400e406837656a057e0 (patch) | |
| tree | 54c873c7e84b70f677f223abce32df3cd9ad3743 /bs_button/src/main.cpp | |
| parent | bc34f55c1abfca72c2ab5f6e0722b56168202366 (diff) | |
| download | arduino-95e5f22a558beeaac8895400e406837656a057e0.tar.gz arduino-95e5f22a558beeaac8895400e406837656a057e0.tar.bz2 arduino-95e5f22a558beeaac8895400e406837656a057e0.zip | |
add bs_button
Diffstat (limited to 'bs_button/src/main.cpp')
| -rw-r--r-- | bs_button/src/main.cpp | 260 |
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" | ||
| 52 | const unsigned char *tracks[] = { | ||
| 53 | alert_mp3, | ||
| 54 | manuel_mp3, | ||
| 55 | rickroll_mp3, | ||
| 56 | llama_mp3, | ||
| 57 | kit_mp3, | ||
| 58 | starwars_mp3 | ||
| 59 | }; | ||
| 60 | const 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 | }; | ||
| 68 | long track_count = sizeof(tracks) / sizeof(unsigned char*); | ||
| 69 | |||
| 70 | #define _STR(s) #s | ||
| 71 | #define STR(s) _STR(s) | ||
| 72 | const String mqtt_clientId = "BSButton-" + String(ESP.getChipId()) | ||
| 73 | + "/v" + STR(FIRMWARE_VERSION); | ||
| 74 | const char* mqtt_topic_ping = MQTT_BASE "/ping"; | ||
| 75 | const char* mqtt_topic_cmd = MQTT_BASE "/command"; | ||
| 76 | const String mqtt_topic_state = String(MQTT_BASE) + "/" + String(ESP.getChipId()); | ||
| 77 | |||
| 78 | class LedControl; | ||
| 79 | bool mqttLoop(); | ||
| 80 | void mqttCallback(char *topic, byte *payload, unsigned int length); | ||
| 81 | void blinkLed(const unsigned long interval); | ||
| 82 | void checkFirmwareUpdate(); | ||
| 83 | |||
| 84 | WiFiClient wifi_client; | ||
| 85 | PubSubClient mqtt(wifi_client); | ||
| 86 | Bounce button = Bounce(); | ||
| 87 | LedControl led(PIN_LED, LED_ON); | ||
| 88 | |||
| 89 | AudioGeneratorMP3 *mp3; | ||
| 90 | AudioFileSourcePROGMEM *file; | ||
| 91 | AudioOutputI2SNoDAC *out; | ||
| 92 | |||
| 93 | void 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 | |||
| 129 | void 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 | |||
| 167 | bool 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 | |||
| 189 | void 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 | |||
| 230 | void 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 | } | ||
