/** * Flowerpot Device Firmware * * Copyright © 2021 Jesse Morgan * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the “Software”), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include #include #include #include #include "Seeed_mbedtls.h" #include "config.h" // IO Pin Configuration #define BATTERY_SWITCH D6 #define MEASURE_SWITCH D8 // Wifi ESP8266WiFiMulti WiFiMulti; // HMAC Context mbedtls_md_context_t ctx; const mbedtls_md_type_t MD_TYPE = MBEDTLS_MD_SHA256; #define HMAC_SIZE_BYTES 32 const char* HEX_BYTE = "0123456789ABCDEF"; // The length of the secret key defined in config.h #define SECRET_KEY_LEN sizeof(SECRET_KEY) - sizeof(SECRET_KEY[0]) // Generate an HMAC signature for a payload. const char* generate_signature(const char* payload, size_t len) { byte hmacResult[HMAC_SIZE_BYTES]; static char hexstring[2 * HMAC_SIZE_BYTES + 1]; // Generate the HMAC mbedtls_md_hmac_starts(&ctx, (const unsigned char *) SECRET_KEY, SECRET_KEY_LEN); mbedtls_md_hmac_update(&ctx, (const unsigned char *) payload, len); mbedtls_md_hmac_finish(&ctx, hmacResult); // Encode as a hex string for (int i = 0; i < HMAC_SIZE_BYTES; i++) { hexstring[2 * i] = HEX_BYTE[(hmacResult[i] >> 4) & 0x0F]; hexstring[2 * i + 1] = HEX_BYTE[hmacResult[i] & 0xF]; } hexstring[2 * HMAC_SIZE_BYTES] = 0; return hexstring; } // Read the ADC and return a value between 0 and 1. float read_value(int pin) { pinMode(A0, INPUT); // Connect load to the ADC digitalWrite(pin, HIGH); // Give things a second to normalize delay(100); int raw; // The ADC will return a value from 0 to 1024, // corresponding to a voltage range between 0 and 1 volts. raw = analogRead(A0); // Disconnect load from the ADC digitalWrite(pin, LOW); return raw / 1024.0; } void setup() { Serial.begin(115200); Serial.println("\n\n"); // Initialize the output variables as outputs pinMode(LED_BUILTIN, OUTPUT); #ifdef HAS_BATTERY pinMode(BATTERY_SWITCH, OUTPUT); #endif pinMode(MEASURE_SWITCH, OUTPUT); // Set outputs to LOW digitalWrite(LED_BUILTIN, LOW); #ifdef HAS_BATTERY digitalWrite(BATTERY_SWITCH, LOW); #endif digitalWrite(MEASURE_SWITCH, LOW); for (uint8_t t = 4; t > 0; t--) { Serial.printf("[SETUP] WAIT %d...\n", t); Serial.flush(); delay(1000); } Serial.printf("Hello, my name is %x, you killed my father...\n", system_get_chip_id()); Serial.printf("Key len %d\n", SECRET_KEY_LEN); WiFi.mode(WIFI_STA); WiFiMulti.addAP("your_network", "your_password?"); // Prepare the HMAC context mbedtls_md_init(&ctx); mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MD_TYPE), 1); } void loop() { // wait for WiFi connection if ((WiFiMulti.run() == WL_CONNECTED)) { #ifdef USE_TLS WiFiClientSecure client; client.setFingerprint(FINGERPRINT); #else WiFiClient client; #endif HTTPClient http; Serial.print("[HTTP] begin...\n"); digitalWrite(LED_BUILTIN, LOW); if (http.begin(client, ENDPOINT)) { // HTTP http.addHeader("Content-Type", "application/x-www-form-urlencoded"); Serial.print("[HTTP] PUT...\n"); // start connection and send HTTP header #ifdef HAS_BATTERY // Get current battery state. Serial.println("Reading battery..."); float battery_value = read_value(BATTERY_SWITCH); #else float battery_value = 1.0; #endif // Get the current resistance Serial.println("Reading R..."); float value = read_value(MEASURE_SWITCH); Serial.printf("Raw measure value = %f\n", value); value = value * 1024.0 / 938.0; Serial.printf("Calibrated measure value = %f\n", value); float r = 320000.0 / value - 320000.0; Serial.printf("R = %f\n", r); // Payload const size_t payload_length = 1024; char payload[payload_length]; int len = snprintf(payload, payload_length, "battery_value=%0.2f&device_id=%08x&value=%0.2f&signature=", battery_value, system_get_chip_id(), r); if (len + 65 <= payload_length) { const char* signature = generate_signature(payload, len - 11); strncpy(payload + len, signature, 65); } else { Serial.printf("Overflow! '%s'\n", payload); } Serial.printf("Putting payload '%s'\n", payload); int httpCode = http.PUT(payload); // httpCode will be negative on error if (httpCode > 0) { // HTTP header has been send and Server response header has been handled Serial.printf("[HTTP] PUT... code: %d\n", httpCode); // file found at server if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { String payload = http.getString(); Serial.println(payload); } } else { Serial.printf("[HTTP] PUT... failed, error: %s\n", http.errorToString(httpCode).c_str()); } http.end(); } else { Serial.printf("[HTTP} Unable to connect\n"); } digitalWrite(LED_BUILTIN, HIGH); Serial.printf("Nighty night.\n"); #ifdef HAS_BATTERY ESP.deepSleep(3600 * 1000000); #else ESP.deepSleep(900 * 1000000); #endif } }