|
M5Stack IoT Suite ESP32 Development Board |
x 1 | |
|
BME680Bosch Sensortec
|
x 1 | |
|
AK9753Sparkfun
|
x 1 | |
|
TCA9548A IIC multiplex expansion module |
x 1 |
|
arduino IDEArduino
|
|
|
Visual Studio Code |
Buddy - A personal home office assistance
What Problem Are We Talking About ?
Corona virus out-break has put our lives upside dow, creating new norms. The most obvious impact of COVID-19 on the labor force is the sharp increase in employees working remotely. Some companies are already planning to shift to flexible workspaces after positive experiences with remote work during the pandemic, a move that will reduce the overall space they need and bring fewer workers into offices each day. A survey of 278 executives by McKinsey in August 2020 found that on average, they planned to reduce office space by 30 percent [source ]
While WFH provided flexibility and cost reduction for companies, there are some serious side effects. Recent studies have indicated, work from home brought serious physical and mental health issues impacting overall productivity of a person and after work life. Most of key factors are
- Improper work schedule, sitting on chair/couch for extensive period of time
- Less physical activity
- Inadequate ambient light which makes person less energetic after work
- Improper working temperature and humidity
- Improper indoor air quality
Based on statistics 1/3 of the population working remotely don't have dedicated or proper home office. When we are in office, most of the environmental measurements are monitored/controlled by office infrastructure.
Impact of temperature and humidity on productivity
Recent studies have shown that slightly warmer temperatures are now considered ideal for productivity levels. Most used to consider 70 to 73 degrees Fahrenheit as the best temperature for the office, but a Cornell study found that up to 77 degrees Fahrenheit is now considered optimal.
There are a number of factors to consider when deciding on the right temperature for your office. The first one is, are there women in the office? Studies have shown that women are more productive in warmer office temperatures. Other things to consider are how many windows there are in the office and how tall the ceilings are. Large windows will bring in more sunlight and make the room warmer, while high ceilings can create drafts and make the room feel colder. Having a good understanding of the building and the people in it is key to finding the ideal temperature.
It’s important to consider humidity when determining the ideal office temperature. If the air is too humid people are more likely to sweat and feel tired. On the other hand, lower humidity can make the air feel colder than it actually is, leading to discomfort and dryness. An ideal humidity level is around 40% for year-round comfort.
The Importance of Good Lighting on Productivity
Lighting makes a tangible impact on employee mood, motivation, and productivity. Studies have demonstrated that spending time in areas with the right lighting can boost vitamin D levels, improve sleep, fight seasonal depression, and cultivate a positive outlook.
Research also revealed that working in dim light for several days increases stress on eyes and brain fatigue, as a result, person feels low on energy and sleepy after office hours.
A Sedentary Lifestyle When Working From Home
Many professionals have had to drastically alter their daily activities to integrate remote work into their lives this past year. While this meant working from the comfort of their own homes, it also may have led to a more sedentary lifestyle than the naturally active one they once enjoyed when commuting to work daily.
A lack of physical activity can lead to severe problems for a human body, including obesity, heart disease, diabetes and more, along with the depression and anxiety that can arise from having to deal with such maladies. For those who have not yet returned to the office, what is the best way to recover from an increasingly inactive lifestyle and make sure they’re getting enough exercise to keep their mind and body healthy?
How Technology Can Help ?
Using technology we can combat most of the above issues. We can build a smart device connecting a set of sensors which would gather room temperature, humidity, light and indoor air quality. A human presence sensor can be connected to the microcontroller which can detect is the person is sitting for an extended period of time. Based on all these data collected from the device via bluetooth, a mobile app can send the data to the cloud. An algorithm running on cloud can send alerts / suggest recommendation to the person indicating if it's time for a walk or indoor air quality needs attention or need to control the temperature to increase productivity.
Introducing Buddy
Buddy is a smart device built on AWS Edukit ( M5Stack Core 2 ), connecting a set of sensors
- BME680 - To capture room temperature, humidity and indoor air quality
- AK9753 - To capture human movement, it can precisely capture left-right, up-down movement
- Light Sensor - To capture room ambient light
Buddy is accompanying by a mobile app which connects to the device over bluetooth. Device runs an algorithm to calculate productivity considering temperature, humidity, light and IAQ. The productivity percentage is simply a number to indicate productivity. This number can be used to make necessary adjustment to your environment.
App also sends you reminder to take a break from work and walk to break sedentary.
Key Features
- Productivity monitoring and recommendation - Based on sensory data, Buddy calculates the productivity and alerts you if productivity is dropping due to environmental data
- Readiness - Based on light, IAQ, buddy determines your readiness after work. High score indicates you will be more energetic and less sleepy after your work hours.
- Push Notification - You app does not need to be running on foreground. Buddy backend will send push notification via AWS Pinpoint
- Analytics - You can track all the sensor data on the app dashboard
- Production ready backend - Entire backend is built on highly scalable AWS server-less architecture which make this product ready to roll out in the market.
- Simplicity - The app is purposefully made very simple. You get all relevant information right on the dashboard page which opens up when you open the app after successful login. There is a 2nd tab where you can see all analytic data and 3rd tab with some settings.
Software Architecture
A lot to talk about software architecture of this product. As mentioned before, I built this on AWS server-less architecture which means you pay by use, not running a server for 24x7 and paying when your system is not in used. Moreover, all the resources used are fully managed by AWS which means you don't need to worry about security patches, upgrades etc. Moreover all these resources auto scalable, you don't need to worry about scale-up / scale-down.
I am fond of AWS Amplify for some obvious reasons - easy to get started with prototype and deploy in production. Easy integration with Cognito authentication, app sync, pinpoint, lambdas.
User authentication ( signup/signin/signout) is managed by AWS Cognito. When new user signs up, user identity is given access to AWS IOT Core to send data from mobile app. As I am not connecting to AWS IOT Core from Edukit which has secured element, rather I am connecting from mobile app, it's very important to secure the communication. Mobile app can send data to IOT core using only authenticated cognito users.
Code snippet to attach a policy to cognito user identity
I granted permission to all iot actions during proof of concept. You can be specific and it's recommended as well. Important thing to call out here is the "*" in resource property. If you specify a particular topic, it does not work. If you find a solution, please let me know in the comment section. I am curious.
Once mobile app connects to the Edukit via bluetooth, Edukit starts sending data to RX characteristic. Upon receiving data, mobile app sends data to AWS IoT core on a predefined channel along with MAC address is is used as unique identifier of the device.
IOT topic
At the same time, mobile app stores the data to AWS datastore which gets synced with dynamoDB through AppSync.
Amplify Console
dynamoDB
One IoT rule is created to push the message to AWS IOT Event input
I have created a detector model to manage the workflow. This is a "no code" workflow management tool for IoT use cases. You can model your entire workflow logic via AWS console. AWS will automatically manage workflows for all your devices, uniquely identified by the key you specify. Here I am using "mac" address as key identifier.
AWS Edukit as BLE Peripheral
AWS Edukit is acting as a BLE peripheral with below service UUID and two characteristics. The device is discoverable as M5StackCore2. From Swift code, I am discovering the device by service UUID so that BLE communication can continue even when app is not running on foreground.
#define BLENAME "M5StackCore2"
#define SERVICE_UUID "4D7D1101-BA27-40B2-836C-17505C1044D7"
#define TX_CHAR_UUID "4D7D1102-BA27-40B2-836C-17505C1044D7"
#define RX_CHAR_UUID "4D7D1103-BA27-40B2-836C-17505C1044D7"
?
When the device is connected to the app, LED bars turned BLUE to provide a visual indication.
Sensor Connections
As M5Stack has grove connectors, there is no soldering needed. All sensors can be plugged into grove sockets.
Pa I2C Hub connected to Core 2 I2C port
BME680 connected to channel 0 of Pa I2C Hub
AK9753 connected to channel 1 of Pa I2C Hub
Grove Light sensor to Core 2 B port
And that's it.
Let's see it in action
Alright. So, enough of writing, now it's time to show how the entire system works. Check out below video.
What's Next ?
This project was created keeping production deployment in mind. As you can understand, AWS backed backend architecture is highly scalable and we can go from development to production in no time.
With help of some PCB fabricator and partnership, we should be able to make the device for real use.
Buddy app is written in Swift which is only for iOS. I need to think about some hybrid mobile development such as flutter or ionic so that I don't need to maintain separate codebase for iOs, Android, Amazon Fire OS
Want To Replicate ?
As part of the Hackster.io project commitment, I made my project open sourced. Please checkout my github repo in code section where I documented how to clone and build the project
#include <M5Core2.h>
#include "FastLED.h"
#include <ArduinoECCX08.h>
#include <Wire.h>
#include "Adafruit_BME680.h"
#include "WiFi.h"
#include <bsec.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#include "ClosedCube_TCA9548A.h"
//#include "images.h"
#include <driver/i2s.h>
#include "Grove_Human_Presence_Sensor.h"
#define BLE_INTERVAL_IN_SECONDS 120
#define SPRITE_COLOR_DEPTH 16
#define LIGHT_SENSOR 36
TFT_eSprite spr = TFT_eSprite(&M5.Lcd);
//app icons
extern const unsigned char previewR[120264];
extern const unsigned char logo[];
extern const unsigned char temperature_icon[];
extern const unsigned char humidity_icon[];
extern const unsigned char iaq_icon[];
extern const unsigned char bat_icon[];
extern const unsigned char light_icon[];
extern const unsigned char bell_icon[];
#define CONFIG_I2S_BCK_PIN 12 //定义I2S相关端口
#define CONFIG_I2S_LRCK_PIN 0
#define CONFIG_I2S_DATA_PIN 2
#define CONFIG_I2S_DATA_IN_PIN 34
#define Speak_I2S_NUMBER I2S_NUM_0 //定义扬声器端口
#define MODE_MIC 0 //定义工作模式
#define MODE_SPK 1
#define DATA_SIZE 1024
bool InitI2SSpeakOrMic(int mode){ //Init I2S. 初始化I2S
esp_err_t err = ESP_OK;
i2s_driver_uninstall(Speak_I2S_NUMBER); // Uninstall the I2S driver. 卸载I2S驱动
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER), // Set the I2S operating mode. 设置I2S工作模式
.sample_rate = 44100, // Set the I2S sampling rate. 设置I2S采样率
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // Fixed 12-bit stereo MSB. 固定为12位立体声MSB
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // Set the channel format. 设置频道格式
.communication_format = I2S_COMM_FORMAT_I2S, // Set the format of the communication. 设置通讯格式
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Set the interrupt flag. 设置中断的标志
.dma_buf_count = 2, //DMA buffer count. DMA缓冲区计数
.dma_buf_len = 128, //DMA buffer length. DMA缓冲区长度
};
if (mode == MODE_MIC){
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
}else{
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
i2s_config.use_apll = false; //I2S clock setup. I2S时钟设置
i2s_config.tx_desc_auto_clear = true; // Enables auto-cleanup descriptors for understreams. 开启欠流自动清除描述符
}
// Install and drive I2S. 安装并驱动I2S
err += i2s_driver_install(Speak_I2S_NUMBER, &i2s_config, 0, NULL);
i2s_pin_config_t tx_pin_config;
tx_pin_config.bck_io_num = CONFIG_I2S_BCK_PIN; // Link the BCK to the CONFIG_I2S_BCK_PIN pin. 将BCK链接至CONFIG_I2S_BCK_PIN引脚
tx_pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN; // ...
tx_pin_config.data_out_num = CONFIG_I2S_DATA_PIN; // ...
tx_pin_config.data_in_num = CONFIG_I2S_DATA_IN_PIN; // ...
err += i2s_set_pin(Speak_I2S_NUMBER, &tx_pin_config); // Set the I2S pin number. 设置I2S引脚编号
err += i2s_set_clk(Speak_I2S_NUMBER, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); // Set the clock and bitwidth used by I2S Rx and Tx. 设置I2S RX、Tx使用的时钟和位宽
return true;
}
void SpeakInit(void){ // 初始化扬声器
M5.Axp.SetSpkEnable(true); //启用扬声器电源
InitI2SSpeakOrMic(MODE_SPK);
}
void DingDong(void){
size_t bytes_written = 0;
i2s_write(Speak_I2S_NUMBER, previewR, 120264, &bytes_written, portMAX_DELAY);
}
AK9753 movementSensor;
// need to adjust these sensitivities lower if you want to detect more far
// but will introduce error detection
float sensitivity_presence = 4.0;
float sensitivity_movement = 4.0;
int detect_interval = 30; //milliseconds
PresenceDetector detector(movementSensor, sensitivity_presence, sensitivity_movement, detect_interval);
uint32_t last_time;
uint32_t last_ble_send;
uint8_t last_ble_move = 0;
ClosedCube::Wired::TCA9548A tca9548a;
Bsec iaqSensor;
String output;
String mac;
void checkIaqSensorStatus(void);
int t = 0, h = 0, a = 0, p = 0, s = 0, avg = 0;
#define PaHub_I2C_ADDRESS 0x70
#define BME680_DEFAULT_ADDRESS (0x76) //for Grove , use 0x77 for Sparkfun
#define BLENAME "M5StackCore2"
#define SERVICE_UUID "4D7D1101-BA27-40B2-836C-17505C1044D7"
#define TX_CHAR_UUID "4D7D1102-BA27-40B2-836C-17505C1044D7"
#define RX_CHAR_UUID "4D7D1103-BA27-40B2-836C-17505C1044D7"
BLEServer* pServer = NULL;
BLECharacteristic* pTxCharacteristic = NULL;
BLECharacteristic* pRxCharacteristic = NULL;
bool bleConnected = false;
WiFiClient client;
#define LEDS_PIN 25
#define LEDS_NUM 10
CRGB ledsBuff[LEDS_NUM];
Adafruit_BME680 bme680; // I2C
void checkIaqSensorStatus(void)
{
if (iaqSensor.status != BSEC_OK) {
if (iaqSensor.status < BSEC_OK) {
output = "BSEC error code : " + String(iaqSensor.status);
Serial.println(output);
while (true) {
}
} else {
output = "BSEC warning code : " + String(iaqSensor.status);
Serial.println(output);
}
}
if (iaqSensor.bme680Status != BME680_OK) {
if (iaqSensor.bme680Status < BME680_OK) {
output = "BME680 error code : " + String(iaqSensor.bme680Status);
Serial.println(output);
while (true) {
}
} else {
output = "BME680 warning code : " + String(iaqSensor.bme680Status);
Serial.println(output);
}
}
}
class M5StackBLEServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
bleConnected = true;
setLEDBarColor(0, 0, 225);
};
void onDisconnect(BLEServer* pServer) {
bleConnected = false;
setLEDBarColor(255, 255, 255);
}
};
class CharacteristicCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
setLEDBarColor(0, 225, 0);
delay(3000);
setLEDBarColor(0, 0, 225);
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue[i]);
Serial.println();
Serial.println("*********");
}
}
};
void setupBLEServer() {
BLEDevice::init(BLENAME);
pServer = BLEDevice::createServer();
pServer->setCallbacks(new M5StackBLEServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(
TX_CHAR_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
pTxCharacteristic->setValue("00;00;00;00");
pRxCharacteristic = pService->createCharacteristic(
RX_CHAR_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
pRxCharacteristic->setCallbacks(new CharacteristicCallbacks());
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
//pAdvertising->setMinPreferred(0x0);
BLEAdvertisementData adv;
adv.setName(BLENAME);
pAdvertising->setAdvertisementData(adv);
BLEAdvertisementData adv2;
adv2.setCompleteServices(BLEUUID(SERVICE_UUID));
pAdvertising->setScanResponseData(adv2);
BLEDevice::startAdvertising();
mac = BLEDevice::getAddress().toString().c_str();
}
void setup() {
M5.begin();
pinMode(LIGHT_SENSOR, INPUT);
Wire.begin();
tca9548a.address(PaHub_I2C_ADDRESS);
FastLED.addLeds<SK6812, LEDS_PIN>(ledsBuff, LEDS_NUM);
setLEDBarColor(255, 255, 255);
M5.Lcd.setTextColor(RED);
M5.Lcd.setTextSize(3);
//display full screen logo
M5.Lcd.pushImage(0, 0, 320, 240, (uint8_t *)logo);
tca9548a.selectChannel(0);
iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire);
checkIaqSensorStatus();
bsec_virtual_sensor_t sensorList[10] = {
BSEC_OUTPUT_RAW_TEMPERATURE,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_RAW_HUMIDITY,
BSEC_OUTPUT_RAW_GAS,
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
};
iaqSensor.updateSubscription(sensorList, 7, BSEC_SAMPLE_RATE_LP);
checkIaqSensorStatus();
delay(5000);
//Initializing AK9753 sensor
tca9548a.selectChannel(1);
if (movementSensor.initialize() == false) {
Serial.println("Device not found. Check wiring.");
while (1);
}
last_time = millis();
last_ble_send = millis();
last_ble_move = 0;
delay(1000);
setupBLEServer();
//M5.Lcd.pushImage(0, 0, 50, 50, (uint8_t *)logo16_glcd_bmp);
SpeakInit();
DingDong();
delay(100);
//delay(10000);
M5.Lcd.clear(BLACK);
M5.Lcd.setCursor(0, 0);
M5.Lcd.setTextSize(2);
//setup display screen for once
M5.Lcd.drawFastVLine(105,0,240,TFT_LIGHTGREY);
M5.Lcd.drawFastVLine(210,0,240,TFT_LIGHTGREY);
M5.Lcd.drawFastHLine(0,120,320,TFT_LIGHTGREY);
M5.Lcd.pushImage(10, 10, 32, 32, (uint8_t *)temperature_icon);
M5.Lcd.pushImage(125, 10, 32, 32, (uint8_t *)humidity_icon);
M5.Lcd.pushImage(240, 10, 32, 32, (uint8_t *)iaq_icon);
M5.Lcd.pushImage(10, 130, 32, 32, (uint8_t *)bat_icon);
M5.Lcd.pushImage(125, 130, 32, 32, (uint8_t *)light_icon);
M5.Lcd.pushImage(240, 130, 32, 32, (uint8_t *)bell_icon);
delay(1000);
}
void setLEDBarColor(uint32_t r, uint32_t g, uint32_t b) {
FastLED.setBrightness(10);
for (int i = 0; i < LEDS_NUM; i++)
{
ledsBuff[i].setRGB(g, r, b);
}
FastLED.show();
}
void loop() {
M5.update();
// if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000, 200)) {
// DingDong();
// }
if(M5.Touch.ispressed()) {
TouchPoint_t coordinate = M5.Touch.getPressPoint();
Serial.printf("x:%d, y:%d \r\n", coordinate.x, coordinate.y);
if (coordinate.x > 210 && coordinate.y > 180){
//bell sprite tapped
DingDong();
}
}
//M5.Axp.SetLed(1);
tca9548a.selectChannel(1);
detector.loop();
uint32_t now = millis();
if (now - last_time > 100) {
// M5.Lcd.clear(BLACK);
// M5.Lcd.setCursor(0, 0);
// M5.Lcd.setTextSize(3);
int light = analogRead(LIGHT_SENSOR);
int lightPct = map(light,0,4095,0,100);
//M5.Lcd.setTextColor(GREEN);
//M5.Lcd.printf("MAC: %s\n", mac.c_str());
//M5.Lcd.printf("LIGHT: %d\n", light);
float batVol = M5.Axp.GetBatVoltage(); // 4.16
int bVol = (int)(batVol * 100.0);
//M5.Lcd.printf("BAT: %d\n", bVol);
int bPct = 100;
if(batVol >= 4.100){
bPct = 100;
} else if(batVol >= 3.95){
bPct = 75;
} else if(batVol >= 3.80){
bPct = 50;
} else if(batVol >= 3.25){
bPct = 25;
} else{
bPct = 0;
}
uint8_t move = 0; // default value if not movement detected
if (detector.presentField1()) {
//M5.Lcd.setTextColor(GREEN);
Serial.println("IR1: X");
move = 1;
} else {
// M5.Lcd.setTextColor(RED);
// M5.Lcd.println("IR1: 0");
}
if (detector.presentField2()) {
// M5.Lcd.setTextColor(GREEN);
Serial.println("IR2: X");
move = 1;
} else {
// M5.Lcd.setTextColor(RED);
// M5.Lcd.println("IR2: 0");
}
if (detector.presentField3()) {
// M5.Lcd.setTextColor(GREEN);
Serial.println("IR3: X");
move = 1;
} else {
// M5.Lcd.setTextColor(RED);
//Serial.println("IR3: 0");
}
if (detector.presentField4()) {
// M5.Lcd.setTextColor(GREEN);
Serial.println("IR4: X");
move = 1;
} else {
// M5.Lcd.setTextColor(RED);
// M5.Lcd.println("IR4: 0");
}
// uint8_t m = detector.getMovement(); //read movement state will clear it
// //M5.Lcd.setTextColor(WHITE);
// //plot a pulse for movement between 1-3
// if (m & MOVEMENT_FROM_1_TO_3) {
// //M5.Lcd.println("1 TO 3");
// move = 1; //movement left to right
// Serial.println("Movement");
// } else if (m & MOVEMENT_FROM_3_TO_1) {
// //M5.Lcd.println("3 TO 1");
// move = 2; //movement right to left
// Serial.println("Movement");
// } else {
// //M5.Lcd.println("NA");
// }
// //Serial.print(detector.getDerivativeOfDiff24());
// //Serial.print(" ");
// //plot a pulse for movement between 2-4
// if (m & MOVEMENT_FROM_2_TO_4) {
// //M5.Lcd.println("2 TO 4");
// move = 3; // up to down
// Serial.println("Movement");
// } else if (m & MOVEMENT_FROM_4_TO_2) {
// //M5.Lcd.println("4 TO 2");
// move = 4; //down to up
// Serial.println("Movement");
// } else {
// //M5.Lcd.println("NA");
// }
if( move != 0 ){
Serial.printf("Setting move to 1 for value %d\n", move);
last_ble_move = 1;
}
tca9548a.selectChannel(0);
if (iaqSensor.run()) { // If new data is available
t = (int) iaqSensor.temperature * 1.8 + 32;
h = iaqSensor.humidity;
a = iaqSensor.iaq;
p = (int) (iaqSensor.pressure / 100);
spr.createSprite(100, 50);
spr.fillSprite(TFT_BLACK);
spr.setTextColor(TFT_LIGHTGREY);
spr.setTextSize(3);
spr.drawNumber(t, 5, 5);
spr.drawString("F", 45, 5);
spr.pushSprite(0, 50);
spr.deleteSprite();
//humidity
spr.setColorDepth(SPRITE_COLOR_DEPTH);
spr.createSprite(103, 70);
if(h > 70){
spr.fillSprite(TFT_RED);
}else{
spr.fillSprite(TFT_BLACK);
}
spr.setTextColor(TFT_LIGHTGREY);
spr.setTextSize(3);
spr.drawNumber(h, 15, 15);
spr.drawString("%", 60, 15);
spr.pushSprite(106, 50);
spr.deleteSprite();
spr.createSprite(80, 50);
spr.fillSprite(TFT_BLACK);
spr.setTextColor(TFT_LIGHTGREY);
spr.setTextSize(3);
spr.drawNumber(a, 5, 5);
//spr.drawString("%", 45, 5);
spr.pushSprite(230, 50);
spr.deleteSprite();
spr.createSprite(80, 50);
spr.fillSprite(TFT_BLACK);
spr.setTextColor(TFT_LIGHTGREY);
spr.setTextSize(3);
spr.drawNumber(bPct, 5, 5);
spr.drawString("%", 65, 5);
spr.pushSprite(0, 170);
spr.deleteSprite();
//light
spr.createSprite(103, 70);
if(lightPct < 50){
spr.fillSprite(TFT_RED);
}else{
spr.fillSprite(TFT_BLACK);
}
spr.setTextColor(TFT_LIGHTGREY);
spr.setTextSize(3);
spr.drawNumber(lightPct, 15, 15);
spr.drawString("%", 60, 15);
spr.pushSprite(106, 170);
spr.deleteSprite();
//bell
spr.createSprite(103, 70);
if(light > 70){
spr.fillSprite(TFT_GREEN);
spr.setTextColor(TFT_BLACK);
}else{
spr.fillSprite(TFT_BLACK);
spr.setTextColor(TFT_LIGHTGREY);
}
spr.setTextSize(5);
spr.drawNumber(0, 30, 15);
spr.pushSprite(211, 170);
spr.deleteSprite();
delay(1000);
if ( bleConnected && (now -last_ble_send > BLE_INTERVAL_IN_SECONDS * 1000 )) {
char buf[72];
sprintf(buf, "%s;%d;%d;%d;%d;%d;%d", mac.c_str(), t, h, a, lightPct,last_ble_move,bPct);
Serial.println(String(buf).c_str());
pTxCharacteristic->setValue(String(buf).c_str());
pTxCharacteristic->notify();
last_ble_send = now;
last_ble_move = 0;
}
} else {
checkIaqSensorStatus();
}
last_time = now;
}
delay(1);
}
Buddy - A personal home office assistance
- Comments(0)
- Likes(1)
- Sebastian Mackowiak Mar 21,2023
- 0 USER VOTES
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
More by mithundotdas
- Mahout - Save The Elephants ?? Save The ElephantsLet's work together and save the beautiful elephants using cutting edge technol...
- Smart Indoor Harvesting Using Wio Terminal & Blynk MotivationThis project is basically designed and programmed by my daughter, Sashrika with little hel...
- A. Eye - Watch out for vehicles This is a getting started guide for beginners to Intel Compute Stick and OpenVINO. I will be using p...
- Touchless ATM using Augmented Reality Stop The SpreadPrevent spreading of COVID-19 is very critical to flatten the curve. Research has fou...
- Basement Monitoring Using Wio Terminal and Blynk MotivationI live in East Coast of USA where most of the houses have basements, some are finished, so...
- Buddy - A personal home office assistance What Problem Are We Talking About ?Corona virus out-break has put our lives upside dow, creating new...
- AI powered thermal camera for safe camping The ProblemI like camping but I am not a "camping enthusiast", I usually camp once or twice a year w...
- Pet Activity Tracker using XIAO BLE Sense & Edge Impulse StoryWhy should human have all the fitness trackers? Our pets deserve more to stay active. I am usin...
- Protect Peatlands for people and planet with help of SensiML The 1997 Indonesia fire burned 9.7– 11.7 million ha on Borneo and Sumatra, destroying 4.5–6 million ...
-
-
-
3D printed Enclosure Backplate for Riden RD60xx power supplies
81 1 1 -
-
-
-
Sega Master System RGB Encoder Switcher Z80 QSB v1.2
71 0 0 -
18650 2S2P Battery Charger, Protection and 5V Output Board
107 0 0 -
High Precision Thermal Imager + Infrared Thermometer | OpenTemp
526 0 7 -
Sony PlayStation Multi Output Frequency Oscillator (MOFO) v1
147 0 2 -