Skip to content

Instantly share code, notes, and snippets.

@takeru
Last active September 18, 2021 05:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takeru/c1505539a3621898d1318d0ba15c51ca to your computer and use it in GitHub Desktop.
Save takeru/c1505539a3621898d1318d0ba15c51ca to your computer and use it in GitHub Desktop.
Automatic ventilation system for comfortable sleep
import React, {useEffect} from "react";
import Amplify, {Auth} from 'aws-amplify';
import awsconfig from './aws-exports';
import {withAuthenticator} from "@aws-amplify/ui-react";
import { PubSub } from 'aws-amplify';
import { AWSIoTProvider } from '@aws-amplify/pubsub';
Amplify.addPluggable(new AWSIoTProvider({
aws_pubsub_region: 'ap-northeast-1',
aws_pubsub_endpoint: 'wss://a15o79dfbws0i-ats.iot.ap-northeast-1.amazonaws.com/mqtt',
}));
Amplify.configure(awsconfig);
Auth.currentCredentials().then((info) => {
const identityId = info.identityId;
console.log("identityId=", identityId);
});
// const sub_all = PubSub.subscribe('#').subscribe({
// next: (data) => {
// console.log("MQTT data=", data);
// },
// error: error => console.error(error),
// close: () => console.log('Done'),
// });
function sub(cb){
const values = {};
const change = (reported)=>{
if(reported.temperature){
values.temperature = reported.temperature;
values.humidity = reported.humidity;
}
if(reported.usbCurrent){
values.fanSpeed = reported.fanSpeed;
values.usbCurrent = reported.usbCurrent;
values.ledBrightness = reported.ledBrightness;
}
cb(JSON.parse(JSON.stringify(values)));
};
const sub1 = PubSub.subscribe('$aws/things/012395fb0a29199a01/shadow/update/documents').subscribe({
next: (data) => {
const reported = data.value.current.state.reported;
console.log("update: temperature=", reported.temperature, "humidity=", reported.humidity);
change(reported);
},
error: error => console.error(error),
close: () => console.log('Done'),
});
const sub2 = PubSub.subscribe('$aws/things/M5StickC-003/shadow/update/documents').subscribe({
next: (data) => {
const reported = data.value.current.state.reported;
console.log("update: fanSpeed=", reported.fanSpeed, "usbCurrent=", reported.usbCurrent, "ledBrightness=", reported.ledBrightness);
change(reported);
},
error: error => console.error(error),
close: () => console.log('Done'),
});
const sub3 = PubSub.subscribe('$aws/things/012395fb0a29199a01/shadow/get/accepted').subscribe({
next: (data) => {
const reported = data.value.state.reported;
console.log("get: temperature=", reported.temperature, "humidity=", reported.humidity);
change(reported);
},
error: error => console.error(error),
close: () => console.log('Done'),
});
const sub4 = PubSub.subscribe('$aws/things/M5StickC-003/shadow/get/accepted').subscribe({
next: (data) => {
const reported = data.value.state.reported;
console.log("get: fanSpeed=", reported.fanSpeed, "usbCurrent=", reported.usbCurrent, "ledBrightness=", reported.ledBrightness);
change(reported);
},
error: error => console.error(error),
close: () => console.log('Done'),
});
setTimeout(()=>{
PubSub.publish('$aws/things/012395fb0a29199a01/shadow/get', "");
PubSub.publish('$aws/things/M5StickC-003/shadow/get', "");
}, 1000);
return ()=>{
console.log("unsubscribe1");
sub1.unsubscribe();
sub2.unsubscribe();
sub3.unsubscribe();
sub4.unsubscribe();
console.log("unsubscribe2");
};
}
function App() {
const [currentUserName, setCurrentUserName] = React.useState("");
const [values, setValues] = React.useState({});
useEffect(() => {
const init = async() => {
const currentUser = await Auth.currentAuthenticatedUser();
setCurrentUserName(currentUser.username);
}
init()
}, []);
useEffect(() => {
return sub((values)=>{
setValues(values);
});
}, []);
const signOut = async() => {
try {
await Auth.signOut();
} catch (error) {
console.log('error signing out: ', error);
}
document.location.reload();
}
const setLedBrightness = async (b) => {
const msg = {state:{desired:{ledBrightness:b}}};
await PubSub.publish('$aws/things/M5StickC-003/shadow/update', msg);
}
const setFanSpeed = async (s) => {
const msg = {state:{desired:{fanSpeed:s}}};
console.log(JSON.stringify(msg));
await PubSub.publish('$aws/things/M5StickC-003/shadow/update', msg);
}
return (
<div>
<h1>username={currentUserName}</h1>
<button onClick={signOut}>signOut</button>
<ul>
<li>temperature={values.temperature}</li>
<li>humidity={values.humidity}</li>
<li>fanSpeed={values.fanSpeed}</li>
<li>usbCurrent={values.usbCurrent}</li>
<li>ledBrightness={values.ledBrightness}</li>
</ul>
<div>
<button onClick={()=>{ setLedBrightness(1); }}>LED ON</button>
<button onClick={()=>{ setLedBrightness(0); }}>LED OFF</button>
</div>
<div>
<button onClick={()=>{ setFanSpeed(1); }}>FAN ON</button>
<button onClick={()=>{ setFanSpeed(0); }}>FAN OFF</button>
</div>
</div>
);
}
export default withAuthenticator(App);
/*
* AWS IoT EduKit - Core2 for AWS IoT EduKit
* Smart Thermostat v1.2.2
* main.c
*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file main.c
* @brief simple MQTT publish, subscribe, and device shadows for use with AWS IoT EduKit reference hardware.
*
* This example takes the parameters from the build configuration and establishes a connection to AWS IoT Core over MQTT.
*
* Some configuration is required. Visit https://edukit.workshop.aws
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "aws_iot_config.h"
#include "aws_iot_log.h"
#include "aws_iot_version.h"
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_shadow_interface.h"
#include "core2forAWS.h"
#include "wifi.h"
#include "ui.h"
#include "switchbot_meter.h"
static const char *TAG = "MAIN";
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200
/* CA Root certificate */
extern const uint8_t aws_root_ca_pem_start[] asm("_binary_aws_root_ca_pem_start");
extern const uint8_t aws_root_ca_pem_end[] asm("_binary_aws_root_ca_pem_end");
/* Default MQTT HOST URL is pulled from the aws_iot_config.h */
char HostAddress[255] = AWS_IOT_MQTT_HOST;
/* Default MQTT port is pulled from the aws_iot_config.h */
uint32_t port = AWS_IOT_MQTT_PORT;
void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
ESP_LOGI(TAG, "Subscribe callback");
ESP_LOGI(TAG, "%.*s\t%.*s", topicNameLen, topicName, (int) params->payloadLen, (char *)params->payload);
}
void disconnect_callback_handler(AWS_IoT_Client *pClient, void *data) {
ESP_LOGW(TAG, "MQTT Disconnect");
ui_textarea_add("Disconnected from AWS IoT Core...", NULL, 0);
IoT_Error_t rc = FAILURE;
if(NULL == pClient) {
return;
}
if(aws_iot_is_autoreconnect_enabled(pClient)) {
ESP_LOGI(TAG, "Auto Reconnect is enabled, Reconnecting attempt will start now");
} else {
ESP_LOGW(TAG, "Auto Reconnect not enabled. Starting manual reconnect...");
rc = aws_iot_mqtt_attempt_reconnect(pClient);
if(NETWORK_RECONNECTED == rc) {
ESP_LOGW(TAG, "Manual Reconnect Successful");
} else {
ESP_LOGW(TAG, "Manual Reconnect Failed - %d", rc);
}
}
}
static bool shadowUpdateInProgress;
static uint32_t shadowUpdateNextMs = UINT32_MAX;
static uint32_t shadowUpdateAcceptedMs = UINT32_MAX;
static uint32_t switchbotMeterDataReceivedMs = UINT32_MAX;
uint32_t millis(){
return pdTICKS_TO_MS(xTaskGetTickCount());
}
void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument, void *pContextData) {
IOT_UNUSED(pThingName);
IOT_UNUSED(action);
IOT_UNUSED(pReceivedJsonDocument);
IOT_UNUSED(pContextData);
shadowUpdateInProgress = false;
char* msg = "";
if(SHADOW_ACK_TIMEOUT == status) {
msg = "Update timed out";
ESP_LOGW(TAG, "%s", msg);
shadowUpdateNextMs = millis() + 10*1000;
} else if(SHADOW_ACK_REJECTED == status) {
msg = "Update rejected";
ESP_LOGW(TAG, "%s", msg);
shadowUpdateNextMs = millis() + 10*1000;
} else if(SHADOW_ACK_ACCEPTED == status) {
msg = "Update accepted";
ESP_LOGI(TAG, "%s", msg);
shadowUpdateAcceptedMs = millis();
}
char tmp[50];
snprintf(tmp, sizeof(tmp), "[%d] %s\n", millis()/1000, msg);
ui_textarea_add(tmp, NULL, 0);
}
void ledColor_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
IOT_UNUSED(pJsonString);
IOT_UNUSED(JsonStringDataLen);
char * ledColor = (char *) (pContext->pData);
if(pContext != NULL) {
ESP_LOGI(TAG, "Delta - ledColor changed to %s", ledColor);
}
if(strcmp(ledColor, "red") == 0) {
ESP_LOGI(TAG, "setting side LEDs to red");
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_LEFT, 0xFF0000);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_RIGHT, 0xFF0000);
Core2ForAWS_Sk6812_Show();
} else if(strcmp(ledColor, "blue") == 0) {
ESP_LOGI(TAG, "setting side LEDs to blue");
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_LEFT, 0x0000FF);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_RIGHT, 0x0000FF);
Core2ForAWS_Sk6812_Show();
}else if(strlen(ledColor) == 12){
ESP_LOGI(TAG, "setting side LEDs to %s", ledColor);
char s[7];
strncpy(s, ledColor, 6);
long left = strtol(s, NULL, 16);
strncpy(s, ledColor+6, 6);
long right = strtol(s, NULL, 16);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_LEFT, left);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_RIGHT, right);
Core2ForAWS_Sk6812_Show();
} else {
ESP_LOGI(TAG, "clearing side LEDs");
Core2ForAWS_Sk6812_Clear();
Core2ForAWS_Sk6812_Show();
}
}
void boolValue2_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
IOT_UNUSED(pJsonString);
IOT_UNUSED(JsonStringDataLen);
if(pContext != NULL) {
bool* pBoolValue2 = (bool*)(pContext->pData);
ESP_LOGI(TAG, "Delta - boolValue2 state changed to %d", *pBoolValue2);
}
}
char ledColor[13] = "";
bool boolValue2 = false;
float temperature = 0.0f;
int32_t humidity = 0;
int32_t battery = 0;
float core2_battery_voltage = 0.0f;
// helper function for working with audio data
long map(long x, long in_min, long in_max, long out_min, long out_max) {
long divisor = (in_max - in_min);
if(divisor == 0){
return -1; //AVR returns -1, SAM returns 0
}
return (x - in_min) * (out_max - out_min) / divisor + out_min;
}
void aws_iot_task(void *param) {
IoT_Error_t rc = FAILURE;
char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
jsonStruct_t ledColor_Actuator;
ledColor_Actuator.cb = ledColor_Callback;
ledColor_Actuator.pKey = "ledColor";
ledColor_Actuator.pData = &ledColor;
ledColor_Actuator.type = SHADOW_JSON_STRING;
ledColor_Actuator.dataLength = sizeof(ledColor);
jsonStruct_t boolValue2_Actuator;
boolValue2_Actuator.cb = boolValue2_Callback;
boolValue2_Actuator.pKey = "boolValue2";
boolValue2_Actuator.pData = &boolValue2;
boolValue2_Actuator.type = SHADOW_JSON_BOOL;
boolValue2_Actuator.dataLength = sizeof(bool);
jsonStruct_t temperature_Handler;
temperature_Handler.cb = NULL;
temperature_Handler.pKey = "temperature";
temperature_Handler.pData = &temperature;
temperature_Handler.type = SHADOW_JSON_FLOAT;
temperature_Handler.dataLength = sizeof(float);
jsonStruct_t humidity_Handler;
humidity_Handler.cb = NULL;
humidity_Handler.pKey = "humidity";
humidity_Handler.pData = &humidity;
humidity_Handler.type = SHADOW_JSON_INT32;
humidity_Handler.dataLength = sizeof(int32_t);
jsonStruct_t battery_Handler;
battery_Handler.cb = NULL;
battery_Handler.pKey = "battery";
battery_Handler.pData = &battery;
battery_Handler.type = SHADOW_JSON_INT32;
battery_Handler.dataLength = sizeof(int32_t);
jsonStruct_t core2_battery_voltage_Handler;
core2_battery_voltage_Handler.cb = NULL;
core2_battery_voltage_Handler.pKey = "c2vbat"; // "core2_battery_voltage" --> "Update timed out" with long key name.
core2_battery_voltage_Handler.pData = &core2_battery_voltage;
core2_battery_voltage_Handler.type = SHADOW_JSON_FLOAT;
core2_battery_voltage_Handler.dataLength = sizeof(float);
ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
// initialize the mqtt client
AWS_IoT_Client iotCoreClient;
ShadowInitParameters_t sp = ShadowInitParametersDefault;
sp.pHost = HostAddress;
sp.port = port;
sp.enableAutoReconnect = false;
sp.disconnectHandler = disconnect_callback_handler;
sp.pRootCA = (const char *)aws_root_ca_pem_start;
sp.pClientCRT = "#";
sp.pClientKey = "#0";
#define CLIENT_ID_LEN (ATCA_SERIAL_NUM_SIZE * 2)
char *client_id = malloc(CLIENT_ID_LEN + 1);
ATCA_STATUS ret = Atecc608_GetSerialString(client_id);
if (ret != ATCA_SUCCESS){
ESP_LOGE(TAG, "Failed to get device serial from secure element. Error: %i", ret);
abort();
}
ui_textarea_add("\nDevice client Id:\n>> %s <<\n", client_id, CLIENT_ID_LEN);
ESP_LOGI(TAG, "Device client Id: >> %s <<", client_id);
/* Wait for WiFI to show as connected */
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Shadow Init");
rc = aws_iot_shadow_init(&iotCoreClient, &sp);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "aws_iot_shadow_init returned error %d, aborting...", rc);
abort();
}
ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
scp.pMyThingName = client_id;
scp.pMqttClientId = client_id;
scp.mqttClientIdLen = CLIENT_ID_LEN;
ESP_LOGI(TAG, "Shadow Connect");
rc = aws_iot_shadow_connect(&iotCoreClient, &scp);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "aws_iot_shadow_connect returned error %d, aborting...", rc);
abort();
}
ui_textarea_add("\nConnected to AWS IoT Core and pub/sub to the device shadow state\n", NULL, 0);
/*
* Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
* #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
* #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
*/
rc = aws_iot_shadow_set_autoreconnect_status(&iotCoreClient, true);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "Unable to set Auto Reconnect to true - %d, aborting...", rc);
abort();
}
// register delta callback for ledColor
rc = aws_iot_shadow_register_delta(&iotCoreClient, &ledColor_Actuator);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "Shadow Register Delta Error");
}
// register delta callback for boolValue2
rc = aws_iot_shadow_register_delta(&iotCoreClient, &boolValue2_Actuator);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "Shadow Register Delta Error");
}
// loop and publish changes
while(NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc) {
rc = aws_iot_shadow_yield(&iotCoreClient, 200);
if(SUCCESS != rc){
ESP_LOGE(TAG, "aws_iot_shadow_yield(A) failed. rc=%d", rc);
}
if(NETWORK_ATTEMPTING_RECONNECT == rc || shadowUpdateInProgress) {
rc = aws_iot_shadow_yield(&iotCoreClient, 1000);
if(SUCCESS != rc){
ESP_LOGE(TAG, "aws_iot_shadow_yield(B) failed. rc=%d", rc);
}
// If the client is attempting to reconnect, or already waiting on a shadow update,
// we will skip the rest of the loop.
continue;
}
// START get sensor readings
// MPU6886_GetTempData(&temperature);
// END get sensor readings
// ESP_LOGI(TAG, "*****************************************************************************************");
// ESP_LOGI(TAG, "On Device: ledColor %s", ledColor);
// ESP_LOGI(TAG, "On Device: boolValue2 %s", boolValue2 ? "true" : "false");
// ESP_LOGI(TAG, "On Device: temperature %f", temperature);
// ESP_LOGI(TAG, "On Device: humidity %d", humidity);
// ESP_LOGI(TAG, "On Device: battery %d", battery);
int32_t timer = shadowUpdateNextMs - millis();
ESP_LOGI(TAG, "timer=%.3f", timer/1000.0);
if(timer <= 0){
while(true){
rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
if(SUCCESS != rc){
ESP_LOGE(TAG, "aws_iot_shadow_init_json_document failed. rc=%d", rc);
break;
}
core2_battery_voltage = Core2ForAWS_PMU_GetBatVolt();
rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 6,
&ledColor_Actuator,
&boolValue2_Actuator,
&temperature_Handler,
&humidity_Handler,
&battery_Handler,
&core2_battery_voltage_Handler
);
if(SUCCESS != rc){
ESP_LOGE(TAG, "aws_iot_shadow_add_reported failed. rc=%d", rc);
break;
}
rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
if(SUCCESS != rc){
ESP_LOGE(TAG, "aws_iot_finalize_json_document failed. rc=%d", rc);
break;
}
ESP_LOGI(TAG, "Update Shadow: %s", JsonDocumentBuffer);
rc = aws_iot_shadow_update(&iotCoreClient, client_id, JsonDocumentBuffer,
ShadowUpdateStatusCallback, NULL, 4, true);
if(SUCCESS != rc){
ESP_LOGE(TAG, "aws_iot_shadow_update failed. rc=%d", rc);
break;
}
char tmp[50];
snprintf(tmp, sizeof(tmp), "[%d] %4.1fC/%d%% %d%% %5.3fV\n", millis()/1000, temperature, humidity, battery, core2_battery_voltage);
ui_textarea_add(tmp, NULL, 0);
shadowUpdateInProgress = true;
shadowUpdateNextMs = millis() + 5*60*1000;
break;
}
}
// ESP_LOGI(TAG, "*****************************************************************************************");
//ESP_LOGI(TAG, "Stack remaining for task '%s' is %d bytes", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL));
vTaskDelay(pdMS_TO_TICKS(1000));
// aws_iot_shadow_yield(&iotCoreClient, 1000);
if(6*60*1000 < millis() - shadowUpdateAcceptedMs){
abort();
}
if(2*60*1000 < millis() - switchbotMeterDataReceivedMs){
abort();
}
}
if(SUCCESS != rc) {
ESP_LOGE(TAG, "An error occurred in the loop %d", rc);
}
ESP_LOGI(TAG, "Disconnecting");
rc = aws_iot_shadow_disconnect(&iotCoreClient);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "Disconnect error %d", rc);
}
vTaskDelay(pdMS_TO_TICKS(1000));
abort();
vTaskDelete(NULL);
}
void _switchbot_meter_callback(float _temperature, int8_t _humidity, int8_t _battery){
ESP_LOGI(TAG, "_switchbot_meter_callback temperature=%4.1f humidity=%d battery=%d",
_temperature, _humidity, _battery
);
if(temperature != _temperature || humidity != _humidity || battery != _battery){
shadowUpdateNextMs = millis() + 1*1000;
}
temperature = _temperature;
humidity = _humidity;
battery = _battery;
switchbotMeterDataReceivedMs = millis();
}
void app_main()
{
esp_log_level_set("*", ESP_LOG_DEBUG);
esp_log_level_set("NimBLEScan", ESP_LOG_WARN);
Core2ForAWS_Init();
// Core2ForAWS_Display_SetBrightness(30);
Core2ForAWS_LED_Enable(0);
for(int i=0; i<5; i++){
Core2ForAWS_Sk6812_SetColor(i+0, i%2==0 ? 0x040000 : 0x000000);
Core2ForAWS_Sk6812_SetColor(i+5, i%2==0 ? 0x040000 : 0x000000);
}
Core2ForAWS_Sk6812_Show();
ui_init();
initialise_wifi();
shadowUpdateAcceptedMs = millis();
xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", 4096*2, NULL, 5, NULL, 1);
/* Wait for WiFI to show as connected */
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
false, true, portMAX_DELAY);
init_ble(&_switchbot_meter_callback);
switchbotMeterDataReceivedMs = millis();
// xTaskCreate(ble_task, "ble_task", 5000, NULL, 1, NULL);
xTaskCreatePinnedToCore(&ble_task, "ble_task", 4096, NULL, 5, NULL, 1);
}
#include <sys/types.h>
#include <NimBLEDevice.h>
#include "switchbot_meter.h"
static const char *TAG_BLE = "ble";
BLEUUID serviceUUID = BLEUUID("cba20d00-224d-11e6-9fb8-0002a5d5c51b");
BLEUUID serviceDataUUID = BLEUUID("00000d00-0000-1000-8000-00805f9b34fb");
//BLEAddress addr01 = BLEAddress("ee:33:dc:9c:72:61"); // meter1
BLEAddress addr02 = BLEAddress("d6:09:18:89:b9:56"); // meter2
//BLEAddress addr03 = BLEAddress("ff:fb:c4:aa:4f:f5"); // meter3
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
switchbot_meter_callback_t callback = NULL;
public:
MyAdvertisedDeviceCallbacks(switchbot_meter_callback_t cb){
callback = cb;
}
void onResult(BLEAdvertisedDevice* advertisedDevice) {
//ESP_LOGI(TAG_BLE, "Advertised Device: %s", advertisedDevice->toString().c_str());
if(advertisedDevice->getAddress().equals(addr02)){
// OK
}else{
return;
}
if(!advertisedDevice->haveServiceUUID()) return;
if(!advertisedDevice->getServiceUUID().equals(serviceUUID)) return;
//ESP_LOGI(TAG_BLE, "SwitchBot Meter: %s", advertisedDevice->toString().c_str());
if(!advertisedDevice->haveServiceData()) return;
//printf("ServiceDataUUID=%s\n", advertisedDevice->getServiceDataUUID().toString().c_str());
std::string s = advertisedDevice->getServiceData();
//printf("ServiceData len=%d [", s.length());
//for(int i=0; i<s.length(); i++){
// printf("%02X ", s.c_str()[i]);
//}
//printf("]\n");
if(!advertisedDevice->getServiceDataUUID().equals(serviceDataUUID)) return;
const char* servicedata = s.c_str();
int8_t battery = servicedata[2] & 0b01111111;
bool isTemperatureAboveFreezing = servicedata[4] & 0b10000000;
float temperature = ( servicedata[3] & 0b00001111 ) / 10.0 + ( servicedata[4] & 0b01111111 );
if(!isTemperatureAboveFreezing){
temperature = -temperature;
}
int8_t humidity = servicedata[5] & 0b01111111;
// bool isEncrypted = ( servicedata[0] & 0b10000000 ) >> 7;
// bool isDualStateMode = ( servicedata[1] & 0b10000000 ) >> 7;
// bool isStatusOff = ( servicedata[1] & 0b01000000 ) >> 6;
// bool isTemperatureHighAlert = ( servicedata[3] & 0b10000000 ) >> 7;
// bool isTemperatureLowAlert = ( servicedata[3] & 0b01000000 ) >> 6;
// bool isHumidityHighAlert = ( servicedata[3] & 0b00100000 ) >> 5;
// bool isHumidityLowAlert = ( servicedata[3] & 0b00010000 ) >> 4;
// bool isTemperatureUnitF = ( servicedata[5] & 0b10000000 ) >> 7;
// ESP_LOGI(TAG_BLE, "----");
// ESP_LOGI(TAG_BLE, "address: %s", advertisedDevice->getAddress().toString().c_str());
// ESP_LOGI(TAG_BLE, "battery: %d", battery);
// ESP_LOGI(TAG_BLE, "temperature: %.1f", temperature);
// ESP_LOGI(TAG_BLE, "humidity: %d", humidity);
// ESP_LOGI(TAG_BLE, "isEncrypted: %d", isEncrypted);
// ESP_LOGI(TAG_BLE, "isDualStateMode: %d", isDualStateMode);
// ESP_LOGI(TAG_BLE, "isStatusOff: %d", isStatusOff);
// ESP_LOGI(TAG_BLE, "isTemperatureHighAlert: %d", isTemperatureHighAlert);
// ESP_LOGI(TAG_BLE, "isTemperatureLowAlert: %d", isTemperatureLowAlert);
// ESP_LOGI(TAG_BLE, "isHumidityHighAlert: %d", isHumidityHighAlert);
// ESP_LOGI(TAG_BLE, "isHumidityLowAlert: %d", isHumidityLowAlert);
// ESP_LOGI(TAG_BLE, "isTemperatureUnitF: %d", isTemperatureUnitF);
// ESP_LOGI(TAG_BLE, "----");
ESP_LOGI(TAG_BLE, "SwitchBotMeter: address=%s battery=%d temperature=%.1f humidity=%d",
advertisedDevice->getAddress().toString().c_str(),
battery,
temperature,
humidity
);
if(callback){
(*callback)(temperature, humidity, battery);
}
}
};
BLEScan* pBLEScan = NULL;
int scanDurationSeconds = 5;
void init_ble(switchbot_meter_callback_t cb){
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(cb));
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(100);
pBLEScan->setWindow(99); // less or equal setInterval value
}
void scanCompleteCB(NimBLEScanResults results){
ESP_LOGI(TAG_BLE, "scan complate. count=%d", results.getCount());
pBLEScan->clearResults();
}
void ble_task(void * parameter){
for(;;) {
bool ok = pBLEScan->start(scanDurationSeconds, scanCompleteCB, false);
if(ok){
ESP_LOGI(TAG_BLE, "scan begin");
}
while(pBLEScan->isScanning()){
//ESP_LOGI(TAG_BLE, "scanning...");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
ESP_LOGI(TAG_BLE, "scan end");
//ESP_LOGI(TAG_BLE, "Stack remaining for task '%s' is %d bytes", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL));
vTaskDelay(1000/portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
#pragma once
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef void (* switchbot_meter_callback_t)(float temperature, int8_t humidity, int8_t battery);
void init_ble(switchbot_meter_callback_t cb);
void ble_task(void * parameter);
#ifdef __cplusplus
}
#endif /* __cplusplus */
/*
* AWS IoT EduKit - Core2 for AWS IoT EduKit
* Smart Thermostat v1.2.2
* ui.c
*
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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 <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "core2forAWS.h"
#include "ui.h"
#define MAX_TEXTAREA_LENGTH 1024
static lv_obj_t *active_screen;
static lv_obj_t *out_txtarea;
static lv_obj_t *wifi_label;
static char *TAG = "UI";
static void ui_textarea_prune(size_t new_text_length){
const char * current_text = lv_textarea_get_text(out_txtarea);
size_t current_text_len = strlen(current_text);
if(current_text_len + new_text_length >= MAX_TEXTAREA_LENGTH){
for(int i = 0; i < new_text_length; i++){
lv_textarea_set_cursor_pos(out_txtarea, 0);
lv_textarea_del_char_forward(out_txtarea);
}
lv_textarea_set_cursor_pos(out_txtarea, LV_TEXTAREA_CURSOR_LAST);
}
}
void ui_textarea_add(char *baseTxt, char *param, size_t paramLen) {
if( baseTxt != NULL ){
xSemaphoreTake(xGuiSemaphore, portMAX_DELAY);
if (param != NULL && paramLen != 0){
size_t baseTxtLen = strlen(baseTxt);
size_t bufLen = baseTxtLen + paramLen;
char buf[(int) bufLen];
sprintf(buf, baseTxt, param);
ui_textarea_prune(strlen(buf));
lv_textarea_add_text(out_txtarea, buf);
}
else{
ui_textarea_prune(strlen(baseTxt));
lv_textarea_add_text(out_txtarea, baseTxt);
}
xSemaphoreGive(xGuiSemaphore);
}
else{
ESP_LOGE(TAG, "Textarea baseTxt is NULL!");
}
}
void ui_wifi_label_update(bool state){
xSemaphoreTake(xGuiSemaphore, portMAX_DELAY);
if (state == false) {
lv_label_set_text(wifi_label, LV_SYMBOL_WIFI);
}
else{
char buffer[25];
sprintf (buffer, "#0000ff %s #", LV_SYMBOL_WIFI);
lv_label_set_text(wifi_label, buffer);
}
xSemaphoreGive(xGuiSemaphore);
}
void ui_init() {
xSemaphoreTake(xGuiSemaphore, portMAX_DELAY);
active_screen = lv_scr_act();
wifi_label = lv_label_create(active_screen, NULL);
lv_obj_align(wifi_label,NULL,LV_ALIGN_IN_TOP_RIGHT, 0, 6);
lv_label_set_text(wifi_label, LV_SYMBOL_WIFI);
lv_label_set_recolor(wifi_label, true);
out_txtarea = lv_textarea_create(active_screen, NULL);
lv_obj_set_size(out_txtarea, 300, 180);
lv_obj_align(out_txtarea, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -12);
lv_textarea_set_max_length(out_txtarea, MAX_TEXTAREA_LENGTH);
lv_textarea_set_text_sel(out_txtarea, false);
lv_textarea_set_cursor_hidden(out_txtarea, true);
lv_textarea_set_text(out_txtarea, "Starting!\n");
xSemaphoreGive(xGuiSemaphore);
}
#include <stdint.h>
#include <Wire.h>
uint8_t Wire1_REG_Read(uint8_t device, uint8_t reg){
Wire1.beginTransmission(device);
Wire1.write(reg);
Wire1.endTransmission();
Wire1.requestFrom(device, (uint8_t)1);
uint8_t buf = Wire1.read();
return buf;
}
void Wire1_REG_Write(uint8_t device, uint8_t reg, uint8_t val){
Wire1.beginTransmission(device);
Wire1.write(reg);
Wire1.write(val);
Wire1.endTransmission();
}
void output5v_ctrl(bool on)
{
uint8_t v0 = Wire1_REG_Read(0x34, 0x12);
uint8_t v = v0 & 0b10111111;
if(on){
v |= 0b01000000;
}
if(v!=v0){
Wire1_REG_Write(0x34, 0x12, v);
}
}
#include <M5StickC.h>
#include "AXP192.h"
#ifdef ARDUINO_ARCH_ESP32
#include "esp32-hal-log.h"
#endif
#include <WiFi.h>
#include <WiFiMulti.h>
#include "time.h"
#include "shadow.h"
#include "m5stickc_5v.h"
#include "secrets.h"
void sync_rtc_with_ntp();
WiFiMulti wifiMulti;
#define PIN_LED GPIO_NUM_10
#define PWMCH_LED 0
void setLedBrightness(int16_t power){
int32_t duty = 256 - power;
if(duty<0) duty = 0;
if(256<duty) duty = 256;
ledcWrite(PWMCH_LED, duty); // off=0 max=256
}
void setup() {
esp_log_level_set("*", ESP_LOG_DEBUG);
//esp_log_level_set("aws_iot", ESP_LOG_NONE);
Serial.begin(115200);
Serial.flush();
delay(50);
Serial.print("M5StickC initializing...");
M5.Axp.begin(true, true, false, false, false, false);
Serial.println("OK");
M5.Rtc.begin();
M5.Axp.EnableCoulombcounter();
wifiMulti.addAP(WIFI_SSID, WIFI_PASSWORD);
pinMode(PIN_LED, OUTPUT);
ledcSetup(PWMCH_LED, 12000, 8);
ledcAttachPin(PIN_LED, PWMCH_LED);
setLedBrightness(0);
}
class Every{
unsigned long intervalMs = 1000;
unsigned long nextMs = 0;
public:
Every(unsigned long interval, unsigned long delay){
this->intervalMs = interval;
this->nextMs = millis() + delay;
}
bool alarm(){
if(this->nextMs <= millis()){
this->nextMs = millis() + this->intervalMs;
return true;
}
return false;
}
};
String mac_string(const uint8_t *mac)
{
char macStr[18] = { 0 };
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(macStr);
}
void loop(){
if(M5.Axp.GetBtnPress() == 0x02)
{
esp_restart();
}
M5.update();
output5v_ctrl(1 <= fanSpeed);
delay(1);
if(WiFi.status() != WL_CONNECTED){
uint8_t ret = wifiMulti.run(30 * 1000);
printf("wifiMulti.run: ret=%d\n", ret);
if(ret == WL_CONNECTED) {
uint8_t mac[6];
WiFi.macAddress(mac);
printf("CONNECTED SSID=%s RSSI=%d localIP=%s mac=%s\n", WiFi.SSID().c_str(), WiFi.RSSI(), WiFi.localIP().toString().c_str(), mac_string(mac).c_str());
sync_rtc_with_ntp();
}else{
delay(5000);
}
return;
}
static Every* every_a = new Every(60*1000, 10*1000);
bool update = false;
if(every_a->alarm()){ update = true; }
shadow_loop(update, 1);
/*
static Every* every_b = new Every(10*1000, 0);
if(every_b->alarm()){
RTC_TimeTypeDef t;
RTC_DateTypeDef d;
M5.Rtc.GetTime(&t);
M5.Rtc.GetData(&d);
printf("RTC: %04d-%02d-%02d %02d:%02d:%02d\n", d.Year, d.Month, d.Date, t.Hours, t.Minutes, t.Seconds);
printf("AXP Temp: %.1fC \n", M5.Axp.GetTempInAXP192());
printf("Bat:\n V: %.3fv I: %.3fma\n", M5.Axp.GetBatVoltage(), M5.Axp.GetBatCurrent());
printf("USB:\n V: %.3fv I: %.3fma\n", M5.Axp.GetVBusVoltage(), M5.Axp.GetVBusCurrent());
printf("5V-In:\n V: %.3fv I: %.3fma\n", M5.Axp.GetVinVoltage(), M5.Axp.GetVinCurrent());
printf("Bat power %.3fmw\n", M5.Axp.GetBatPower());
printf("\n");
}
*/
static Every* every_c = new Every(100, 0);
if(every_c->alarm()){
setLedBrightness(ledBrightness);
}
const int usbCurrentHistorySize = 10;
static float usbCurrentHistory[usbCurrentHistorySize];
static uint32_t usbCurrentHistoryIndex = 0;
static Every* every_d = new Every(500, 0);
if(every_d->alarm()){
usbCurrentHistory[usbCurrentHistoryIndex] = M5.Axp.GetVBusCurrent();
usbCurrentHistoryIndex = (usbCurrentHistoryIndex + 1) % usbCurrentHistorySize;
if(usbCurrentHistoryIndex == 0 || 0<=usbCurrent){
float sum = 0.0;
for(int i=0; i<usbCurrentHistorySize; i++){
sum += usbCurrentHistory[i];
}
usbCurrent = sum / usbCurrentHistorySize;
printf("usbCurrent=%6.2f\n", usbCurrent);
}
}
}
void sync_rtc_with_ntp()
{
const char* ntpServer = "ntp.jst.mfeed.ad.jp";
configTime(9 * 3600, 0, ntpServer);
struct tm timeInfo;
if (getLocalTime(&timeInfo)) {
RTC_TimeTypeDef t;
t.Hours = timeInfo.tm_hour;
t.Minutes = timeInfo.tm_min;
t.Seconds = timeInfo.tm_sec;
M5.Rtc.SetTime(&t);
RTC_DateTypeDef d;
d.WeekDay = timeInfo.tm_wday;
d.Month = timeInfo.tm_mon + 1;
d.Date = timeInfo.tm_mday;
d.Year = timeInfo.tm_year + 1900;
M5.Rtc.SetData(&d);
}
}
#define WIFI_SSID "my-ssid"
#define WIFI_PASSWORD "my-passed"
#define AWSIOT_THING_NAME "M5StickC-thing-name"
#define AWSIOT_MQTT_CLIENT_ID "clientid-m5stickc-xxx"
#define AWSIOT_MQTT_HOST "xxxxxxxx-ats.iot.xxxxx.amazonaws.com"
#define AWSIOT_MQTT_PORT 8883
#include <string.h>
#include <stdint.h>
#include "aws_iot_config.h"
#include "aws_iot_log.h"
#include "aws_iot_version.h"
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_shadow_interface.h"
#include "secrets.h"
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200
static const char *TAG = "shadow";
extern const uint8_t aws_root_ca_pem_start[] asm("_binary_aws_root_ca_pem_start");
extern const uint8_t aws_root_ca_pem_end[] asm("_binary_aws_root_ca_pem_end");
extern const uint8_t certificate_pem_crt_start[] asm("_binary_certificate_pem_crt_start");
extern const uint8_t certificate_pem_crt_end[] asm("_binary_certificate_pem_crt_end");
extern const uint8_t private_pem_key_start[] asm("_binary_private_pem_key_start");
extern const uint8_t private_pem_key_end[] asm("_binary_private_pem_key_end");
int8_t fanSpeed = 0;
float temperature = 0.0;
int16_t ledBrightness = 0;
float usbCurrent = 0.0;
bool deltaFlag = false;
static bool shadowUpdateInProgress;
enum {
INACTIVE,
ACTIVE,
ERROR
} status;
void _cb_aws_iot_shadow_update(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument, void *pContextData) {
IOT_UNUSED(pThingName);
IOT_UNUSED(action);
IOT_UNUSED(pReceivedJsonDocument);
IOT_UNUSED(pContextData);
shadowUpdateInProgress = false;
deltaFlag = false;
if(SHADOW_ACK_TIMEOUT == status) {
ESP_LOGE(TAG, "Update timed out");
} else if(SHADOW_ACK_REJECTED == status) {
ESP_LOGE(TAG, "Update rejected");
} else if(SHADOW_ACK_ACCEPTED == status) {
ESP_LOGI(TAG, "Update accepted");
}
}
void fanSpeedActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
IOT_UNUSED(pJsonString);
IOT_UNUSED(JsonStringDataLen);
if(pContext != NULL) {
ESP_LOGI(TAG, "Delta - fanSpeed changed to %d", *(int8_t *) (pContext->pData));
deltaFlag = true;
}
}
void ledBrightnessActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
IOT_UNUSED(pJsonString);
IOT_UNUSED(JsonStringDataLen);
if(pContext != NULL) {
ESP_LOGI(TAG, "Delta - ledBrightness changed to %d", *(int16_t *) (pContext->pData));
deltaFlag = true;
}
}
jsonStruct_t fanSpeedActuator;
jsonStruct_t ledBrightnessActuator;
jsonStruct_t temperatureHandler;
jsonStruct_t usbCurrentHandler;
AWS_IoT_Client mqttClient;
bool _shadow_init(void)
{
IoT_Error_t rc = FAILURE;
fanSpeedActuator.cb = fanSpeedActuate_Callback;
fanSpeedActuator.pData = &fanSpeed;
fanSpeedActuator.pKey = "fanSpeed";
fanSpeedActuator.type = SHADOW_JSON_INT8;
fanSpeedActuator.dataLength = sizeof(int8_t);
ledBrightnessActuator.cb = ledBrightnessActuate_Callback;
ledBrightnessActuator.pData = &ledBrightness;
ledBrightnessActuator.pKey = "ledBrightness";
ledBrightnessActuator.type = SHADOW_JSON_INT16;
ledBrightnessActuator.dataLength = sizeof(int16_t);
temperatureHandler.cb = NULL;
temperatureHandler.pKey = "temperature";
temperatureHandler.pData = &temperature;
temperatureHandler.type = SHADOW_JSON_FLOAT;
temperatureHandler.dataLength = sizeof(float);
usbCurrentHandler.cb = NULL;
usbCurrentHandler.pKey = "usbCurrent";
usbCurrentHandler.pData = &usbCurrent;
usbCurrentHandler.type = SHADOW_JSON_FLOAT;
usbCurrentHandler.dataLength = sizeof(float);
ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
ShadowInitParameters_t sp = ShadowInitParametersDefault;
sp.pHost = AWSIOT_MQTT_HOST;
sp.port = AWSIOT_MQTT_PORT;
sp.pClientCRT = (const char *)certificate_pem_crt_start;
sp.pClientKey = (const char *)private_pem_key_start;
sp.pRootCA = (const char *)aws_root_ca_pem_start;
sp.enableAutoReconnect = false;
sp.disconnectHandler = NULL;
rc = aws_iot_shadow_init(&mqttClient, &sp);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "aws_iot_shadow_init failed. rc=%d", rc);
return false;
}
ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
scp.pMyThingName = AWSIOT_THING_NAME;
scp.pMqttClientId = AWSIOT_MQTT_CLIENT_ID;
scp.mqttClientIdLen = (uint16_t) strlen(AWSIOT_MQTT_CLIENT_ID);
rc = aws_iot_shadow_connect(&mqttClient, &scp);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "aws_iot_shadow_connect failed. rc=%d", rc);
return false;
}
rc = aws_iot_shadow_set_autoreconnect_status(&mqttClient, true);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "aws_iot_shadow_set_autoreconnect_status failed. rc=%d", rc);
return false;
}
rc = aws_iot_shadow_register_delta(&mqttClient, &fanSpeedActuator);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "aws_iot_shadow_register_delta fanSpeedActuator failed. rc=%d", rc);
return false;
}
rc = aws_iot_shadow_register_delta(&mqttClient, &ledBrightnessActuator);
if(SUCCESS != rc) {
ESP_LOGE(TAG, "aws_iot_shadow_register_delta ledBrightness failed. rc=%d", rc);
return false;
}
return true;
}
bool _shadow_deinit(void)
{
IoT_Error_t rc = FAILURE;
rc = aws_iot_shadow_disconnect(&mqttClient);
if(SUCCESS != rc){ ESP_LOGE(TAG, "error: aws_iot_shadow_disconnect. rc=%d", rc); return false; }
rc = aws_iot_shadow_free(&mqttClient);
if(SUCCESS != rc){ ESP_LOGE(TAG, "error: aws_iot_shadow_free. rc=%d", rc); return false; }
return true;
}
bool _shadow_tick(bool update, uint32_t timeout)
{
IoT_Error_t rc = aws_iot_shadow_yield(&mqttClient, timeout);
if(NETWORK_ATTEMPTING_RECONNECT == rc) {
return true;
}
if(NETWORK_RECONNECTED == rc || SUCCESS == rc){
// OK
}else{
ESP_LOGE(TAG, "error: aws_iot_shadow_yield. rc=%d", rc);
return false;
}
if(deltaFlag){ update = true; }
if(update){
if(shadowUpdateInProgress){
return true;
}
char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
if(SUCCESS != rc){ ESP_LOGE(TAG, "error: aws_iot_shadow_init_json_document. rc=%d", rc); return false; }
rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer,
4,
&temperatureHandler,
&fanSpeedActuator,
&ledBrightnessActuator,
&usbCurrentHandler
);
if(SUCCESS != rc){ ESP_LOGE(TAG, "error: aws_iot_shadow_add_reported. rc=%d", rc); return false; }
rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
if(SUCCESS != rc){ ESP_LOGE(TAG, "error: aws_iot_finalize_json_document. rc=%d", rc); return false; }
ESP_LOGI(TAG, "aws_iot_shadow_update: %s", JsonDocumentBuffer);
rc = aws_iot_shadow_update(&mqttClient, AWSIOT_THING_NAME, JsonDocumentBuffer,
_cb_aws_iot_shadow_update, NULL, 4, true);
if(SUCCESS != rc){ ESP_LOGE(TAG, "error: aws_iot_shadow_update. rc=%d", rc); return false; }
shadowUpdateInProgress = true;
}
return true;
}
bool shadow_loop(bool update, uint32_t timeout)
{
switch (status)
{
case INACTIVE: {
bool ok = _shadow_init();
ESP_LOGI(TAG, "_shadow_init: %d", ok);
if(ok){
status = ACTIVE;
}
break;
}
case ACTIVE:
if(!_shadow_tick(update, timeout)){
if(_shadow_deinit()){
status = INACTIVE;
}else{
status = ERROR;
}
}
break;
case ERROR:
return false;
break;
default:
break;
}
return true;
}
#pragma once
#include <stdint.h>
bool shadow_loop(bool update, uint32_t timeout);
extern int8_t fanSpeed;
extern float temperature;
extern int16_t ledBrightness;
extern float usbCurrent;
const AWS = require('aws-sdk');
AWS.config.update({region: 'ap-northeast-1'});
const docClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
const iotData = new AWS.IotData({endpoint: "a15o79dfbws0i-ats.iot.ap-northeast-1.amazonaws.com"});
exports.handler = async (event) => {
const timestamp_begin = (new Date()).getTime() - (1 * 60 * 1000);
const params = {
TableName: 'awsiot_shadow_values',
KeyConditionExpression: 'client_id = :client_id and aws_timestamp >= :timestamp_begin',
ExpressionAttributeValues: {
':client_id': "M5StickC-003",
':timestamp_begin': timestamp_begin
},
ScanIndexForward: false,
Limit: 1
};
const queryResult = await docClient.query(params).promise();
if(queryResult.Items.length == 0){
return {statusCode: 200, body: {result: "error", error: "no items."}};
}
const item = queryResult.Items[0];
console.log("item = ", item);
let fanSpeed = 0;
let ledColor = "000010" + "000010";
if(30.0 <= item.state.reported.temperature){
fanSpeed = 80;
ledColor = "201000" + "201000";
}
const updateResult = await updateFanSpeed(fanSpeed, ledColor);
return {
statusCode: 200,
body: {result: "success", updateResult: updateResult}
};
};
function updateFanSpeed(fanSpeed, ledColor){
const p1 = iotData.updateThingShadow({
thingName: "M5StickC-003",
payload: JSON.stringify({
state: {
desired: {
fanSpeed: fanSpeed
}
}
})
}).promise();
const p2 = iotData.updateThingShadow({
thingName: "012395fb0a29199a01",
payload: JSON.stringify({
state: {
desired: {
ledColor: ledColor
}
}
})
}).promise();
return Promise.all([p1,p2]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment