[READ-ONLY] Mirror of https://github.com/jphastings/jan-poka. Jan Poka is a suite of tools for controlling custom internet-of-things devices that help make your distant friends feel closer.
geolocation hardware mqtt
0

Configure Feed

Select the types of activity you want to include in your feed.

Working with MQTT

+121 -81
+2
.gitignore
··· 3 3 .DS_Store 4 4 /.balena-sync.yml 5 5 /dist/jan-poka 6 + .pio 7 + .vscode
+9
hardware/clock/platformio.ini
··· 12 12 platform = espressif32 13 13 board = firebeetle32 14 14 framework = arduino 15 + lib_deps = 16 + waspinator/AccelStepper@^1.61 17 + knolleary/PubSubClient@^2.8 18 + bblanchon/ArduinoJson@^6.18.5 19 + makuna/NeoPixelBus@^2.6.9 20 + amcewen/HttpClient@^2.2.0 21 + upload_port = /dev/cu.usbserial-0001 22 + monitor_port = /dev/cu.usbserial-0001 23 + monitor_speed = 115200
+110 -81
hardware/clock/src/main.cpp
··· 1 + #include <Arduino.h> 1 2 #include <AccelStepper.h> 2 3 #include <NeoPixelBus.h> 3 4 #include <PubSubClient.h> ··· 26 27 27 28 NeoPixelBus<NeoGrbwFeature, NeoSk6812Method> leds(LED_COUNT, 27); 28 29 29 - HTTPClient httpClient; 30 30 WiFiClient wifiClient; 31 31 PubSubClient mqttClient(wifiClient); 32 32 time_t epoch; ··· 36 36 int sunriseMins = -1; 37 37 int sunsetMins = -1; 38 38 39 + // TODO: Pick good colours; include Warm White? 40 + RgbwColor dayCol(128, 64, 0, 128); 41 + RgbwColor nightCol(0, 0, 128, 0); 42 + RgbwColor offCol(0, 0, 0, 0); 43 + 44 + void setupWifi(); 45 + void setupMQTT(); 46 + void setupTime(); 47 + void setupMotors(); 48 + void setupLEDs(); 49 + 50 + void updateTime(); 51 + void updateClock(); 52 + void updateMotors(); 53 + void updateLEDs(); 54 + void updateMQTT(); 55 + 56 + void handleGeoTarget(char*, byte*, unsigned int); 57 + bool steppersMoving(); 58 + void setSunriseAndSunset(String, String); 59 + int timeToDayMins(int, int); 60 + 61 + int updatedInt(); 62 + bool noNeedToUpdate(); 63 + void setTimezone(double, double); 64 + void normalizeStepper(AccelStepper*); 65 + void moveCircular(AccelStepper*, long); 66 + 39 67 void setupWifi() { 40 68 WiFi.begin(WIFI_SSID, WIFI_PASS); 41 69 while(WiFi.status()!=WL_CONNECTED) { ··· 43 71 } 44 72 } 45 73 74 + void updateMQTT() { 75 + if (!mqttClient.connected()) { 76 + if (!mqttClient.connect(APP_NAME, MQTT_USER, MQTT_PASS)) { 77 + Serial.println("Failed to connect to MQTT broker"); 78 + // TODO: Backoff 79 + return; 80 + } 81 + mqttClient.setCallback(handleGeoTarget); 82 + mqttClient.subscribe(MQTT_TOPIC); 83 + } 84 + mqttClient.loop(); 85 + } 86 + 46 87 void setupMQTT() { 47 88 mqttClient.setServer(MQTT_HOST, MQTT_PORT); 48 - mqttConnectionLoop(); 89 + updateMQTT(); 49 90 } 50 91 51 92 void setupTime() { ··· 55 96 56 97 // Home: 57 98 setTimezone(51.53647542276452, -0.08639983104800102); 58 - // Chris: 59 - //setTimezone(49.27103836424926, -123.15245006680813); 60 - // Venezuela 61 - //setTimezone(10.436620855606654, -66.84207546938133); 62 99 } 63 100 64 101 void setupMotors() { ··· 75 112 leds.Begin(); 76 113 } 77 114 78 - void setup() { 79 - Serial.begin(115200); 80 - 81 - setupWifi(); 82 - setupMotors(); 83 - setupLEDs(); 84 - setupTime(); 85 - setupMQTT(); 86 - Serial.println("Booted"); 87 - } 88 - 89 - void loop() { 90 - time(&epoch); 91 - now = localtime(&epoch); 92 - 93 - stepMin.run(); 94 - stepHour.run(); 95 - 96 - updateClock(); 97 - } 98 - 99 - void mqttConnectionLoop() { 100 - if (!mqttClient.connected()) { 101 - if (!mqttClient.connect(APP_NAME, MQTT_USER, MQTT_PASS)) { 102 - Serial.println("Failed to connect to MQTT broker"); 103 - // TODO: Backoff 104 - return; 105 - } 106 - Serial.println("MQTT connected"); 107 - mqttClient.setCallback(handleGeoTarget); 108 - mqttClient.subscribe(MQTT_TOPIC); 109 - } 110 - mqttClient.loop(); 111 - } 112 - 113 115 void handleGeoTarget(char* topic, byte* payload, unsigned int length) { 116 + Serial.println("MQTT message received"); 114 117 /* Copied from EspMQTTClient: https://github.com/plapointe6/EspMQTTClient/blob/master/src/EspMQTTClient.cpp#L649 */ 115 118 // Convert the payload into a String 116 119 // First, We ensure that we dont bypass the maximum size of the PubSubClient library buffer that originated the payload ··· 127 130 String payloadStr((char*)payload); 128 131 /* end */ 129 132 130 - StaticJsonDocument<512> jsonDoc; 131 - DeserializationError err = deserializeJson(jsonDoc, payload); 133 + StaticJsonDocument<512> doc; 134 + DeserializationError err = deserializeJson(doc, payload); 132 135 if (err != DeserializationError::Ok) { 133 136 Serial.print("Unsuccessful at parsing MQTT JSON: "); 134 - Serial.println(err.f_str()); 137 + Serial.println(err.c_str()); 135 138 return; 136 139 } 137 - setTimezone(jsonDoc["lat"], jsonDoc["lng"]); 140 + setTimezone(doc["lat"], doc["lng"]); 138 141 } 139 142 140 143 bool steppersMoving() { 141 144 return stepMin.distanceToGo() != 0 || stepHour.distanceToGo() != 0; 142 145 } 143 146 144 - void setTimezone(double latitude, double longitude) { 145 - char url[255]; 146 - sprintf(url, TIMEZONE_QUERY, latitude, longitude); 147 - 148 - httpClient.useHTTP10(true); 149 - httpClient.begin(wifiClient, url); 150 - httpClient.GET(); 151 - 152 - StaticJsonDocument<384> doc; 153 - DeserializationError error = deserializeJson(doc, httpClient.getStream()); 154 - 155 - if (error) { 156 - Serial.print("Grabbing timezone details failed: "); 157 - Serial.println(error.c_str()); 158 - return; 159 - } 160 - 161 - // TODO: Deal with DST 162 - configTime(doc["rawOffset"].as<float>() * 3600, 0, NTP_SERVER); 163 - setSunriseAndSunset(doc["sunrise"], doc["sunset"]); 164 - 165 - httpClient.end(); 166 - updateClock(); 167 - } 168 - 169 147 void setSunriseAndSunset(String sunriseStr, String sunsetStr) { 170 148 sunriseMins = timeToDayMins(sunriseStr.substring(11, 13).toInt(), sunriseStr.substring(14, 16).toInt()); 171 149 sunsetMins = timeToDayMins(sunsetStr.substring(11, 13).toInt(), sunsetStr.substring(14, 16).toInt()); ··· 179 157 if (now == 0 || steppersMoving() || noNeedToUpdate()) 180 158 return; 181 159 182 - Serial.print("Setting time to: "); Serial.print(now->tm_hour); Serial.print(":"); Serial.println(now->tm_min); 160 + Serial.print("Setting time to: "); Serial.print(now->tm_hour); Serial.print(":"); Serial.print(now->tm_min); Serial.print(":"); Serial.println(now->tm_sec); 183 161 184 162 updateMotors(); 185 163 updateLEDs(); ··· 200 178 moveCircular(&stepHour, (now->tm_hour + now->tm_min/60.0) * HOURS_STEPS); 201 179 } 202 180 203 - // TODO: Pick good colours; include Warm White? 204 - RgbwColor dayCol(128, 64, 0, 128); 205 - RgbwColor nightCol(0, 0, 128, 0); 206 - RgbwColor offCol(0, 0, 0, 0); 207 - 208 181 void updateLEDs() { 209 182 int nowMins = timeToDayMins(now->tm_hour, now->tm_min); 210 183 // The time in minutes now, scaled to fit into the number of LEDs, offset by half as 0th pixel is at 6 o'clock ··· 225 198 leds.Show(); 226 199 } 227 200 201 + void normalizeStepper(AccelStepper* stepper) { 202 + long pos = stepper->currentPosition(); 203 + if (pos < 0 || pos >= MOTOR_STEPS) { 204 + int mult = pos / MOTOR_STEPS; 205 + stepper->setCurrentPosition((pos - mult * MOTOR_STEPS) % MOTOR_STEPS); 206 + } 207 + } 208 + 228 209 void moveCircular(AccelStepper* stepper, long steps) { 229 210 normalizeStepper(stepper); 230 211 ··· 240 221 stepper->moveTo(-newPos); // -ve for clockwise correction 241 222 } 242 223 243 - void normalizeStepper(AccelStepper* stepper) { 244 - long pos = stepper->currentPosition(); 245 - if (pos < 0 || pos >= MOTOR_STEPS) { 246 - int mult = pos / MOTOR_STEPS; 247 - stepper->setCurrentPosition((pos - mult * MOTOR_STEPS) % MOTOR_STEPS); 224 + void setTimezone(double latitude, double longitude) { 225 + Serial.print("Setting timezone for: "); 226 + Serial.print(latitude); 227 + Serial.print(", "); 228 + Serial.println(longitude); 229 + 230 + char url[255]; 231 + sprintf(url, TIMEZONE_QUERY, latitude, longitude); 232 + 233 + HTTPClient httpClient; 234 + httpClient.useHTTP10(true); 235 + httpClient.begin(wifiClient, url); 236 + httpClient.GET(); 237 + 238 + StaticJsonDocument<512> doc; 239 + DeserializationError err = deserializeJson(doc, httpClient.getStream()); 240 + if (err != DeserializationError::Ok) { 241 + Serial.print("Grabbing timezone details failed: "); 242 + Serial.println(err.c_str()); 243 + return; 248 244 } 245 + 246 + // TODO: Deal with DST 247 + configTime(doc["rawOffset"].as<float>() * 3600, 0, NTP_SERVER); 248 + setSunriseAndSunset(doc["sunrise"], doc["sunset"]); 249 + 250 + httpClient.end(); 251 + updateClock(); 252 + } 253 + 254 + void updateTime() { 255 + time(&epoch); 256 + now = localtime(&epoch); 257 + } 258 + 259 + void setup() { 260 + Serial.begin(115200); 261 + 262 + setupWifi(); 263 + setupMotors(); 264 + setupLEDs(); 265 + setupTime(); 266 + setupMQTT(); 267 + Serial.println("Booted"); 268 + } 269 + 270 + void loop() { 271 + updateTime(); 272 + 273 + stepMin.run(); 274 + stepHour.run(); 275 + 276 + updateClock(); 277 + updateMQTT(); 249 278 }