// TemperatureSensor: a thermometer that Alexa reads, and that tells Alexa when the temperature changed // (Alexa.TemperatureSensor). // // The sensor is a TMP36 on A0 of a Wemos D1 mini, whose A0 takes 0 to 3.2 V; for another sensor replace // readTemperature(). The temperature is read every 2 s. A ChangeReport is sent when it differs by more than // 0.5 degrees from what Alexa was told last, and at most once a minute. #include #include #include // Wi-Fi and the credentials of your Alex2MQTT account const char *WIFI_SSID = ""; const char *WIFI_PASSWORD = ""; const char *ALEXA_USERNAME = ""; const char *ALEXA_PASSWORD = ""; const char *ALEXA_ROOT_TOPIC = ""; const unsigned long READ_EVERY_MS = 2000; const unsigned long REPORT_EVERY_MS = 60000; const float REPORT_DIFFERENCE = 0.5f; // degrees Celsius Alex2ESP alexa; AlexaDevice *sensor; float temperature = 0; // degrees Celsius, as read last float reported = 0; // what the last ChangeReport said bool everReported = false; unsigned long lastRead = 0; unsigned long lastReport = 0; // Joins the Wi-Fi network and returns after 30 s at the latest. Without a connection the sketch carries on: the // ESP8266 keeps trying, and alexa.loop() opens the MQTT session once Wi-Fi is up. void connectWiFi() { WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); Serial.printf("\n[WIFI] Connecting to \"%s\"\n", WIFI_SSID); unsigned long started = millis(); while (WiFi.status() != WL_CONNECTED && millis() - started < 30000) { delay(100); } if (WiFi.status() == WL_CONNECTED) { Serial.printf("[WIFI] Connected, IP address %s\n", WiFi.localIP().toString().c_str()); } else { Serial.printf("[WIFI] No connection after 30 s (status %d): check WIFI_SSID and WIFI_PASSWORD. Still trying.\n", WiFi.status()); } } // TMP36: 0.5 V at 0 degrees Celsius, 10 mV per degree float readTemperature() { float volts = analogRead(A0) * 3.2f / 1023; return (volts - 0.5f) * 100; } void onDirective(AlexaDirective &directive) { if (directive.isReportState()) { directive.stateReport() .addHealthProp(EndpointHealth::OK) .addTemperatureSensorProp(temperature, TemperatureSensorScale::CELSIUS, millis() - lastRead) .send(); return; } directive.error(AlexaErrorType::INVALID_DIRECTIVE, "A thermometer takes no directives").send(); } void reportChange() { bool due = !everReported || millis() - lastReport >= REPORT_EVERY_MS; if (!due || fabs(temperature - reported) <= REPORT_DIFFERENCE || alexa.getState() != Alex2ESPState::CONNECTED) { return; } bool sent = sensor->changeReport(AlexaCause::PERIODIC_POLL) .addTemperatureSensorProp(temperature) .context() .addHealthProp(EndpointHealth::OK) .send(); if (sent) { reported = temperature; everReported = true; lastReport = millis(); } } void setup() { Serial.begin(74880); temperature = readTemperature(); connectWiFi(); // MQTT user name, MQTT password, root topic alexa.begin(ALEXA_USERNAME, ALEXA_PASSWORD, ALEXA_ROOT_TOPIC); // The name Alexa shows, and the id of the endpoint: every device of an account has its own sensor = alexa.getDevice("Room Temperature", "esp-temperature"); sensor->setDisplayCategory(DisplayCategory::TEMPERATURE_SENSOR); sensor->addCapability(AlexaInterfaces::TemperatureSensor)->setProactivelyReported(true); sensor->addCapability(AlexaInterfaces::EndpointHealth); sensor->onDirective(onDirective); } void loop() { alexa.loop(); if (millis() - lastRead >= READ_EVERY_MS) { lastRead = millis(); temperature = readTemperature(); reportChange(); } }