ESP32 eCO2-Telegram-Bot

Place your projects here
Post Reply
User avatar
PeterN
Posts: 366
Joined: Mon Feb 08, 2021 7:56 pm
Location: Krefeld, Germany
Has thanked: 171 times
Been thanked: 203 times
Contact:

ESP32 eCO2-Telegram-Bot

Post by PeterN »

This eCO2 monitor indicates poor air quality via a
  • local NeoPixel-LED-Strip, via a
  • Webinterface and via a
  • TELEGRAM message produced by a built-in telegram bot

IMG_0159.jpg

Hardware: Required are an eCO2-Sensor CCS811 and an ESP32 -SoC-module - preferably an M5Stack "ATOM-matrix" or "ATOM lite" with a build-in NeoPixel-strip. The Hardware components get placed on a simple grid board or a breadboard and are powered from a 5V-USB-power-supply .(5V@min500mA).
IMG_6782.jpg
IMG_0157.jpg
IMG_0158.jpg

The eCO2-Sensor CCS811:
The CCS811 sensor calculates the eCO2-level by meassuring the tVOC (total Volatile Organic Compound) of exhaled air that may be "polluted" by the human lungs. It can not return the absolute CO2-level!
Additionally the sensors sensitivity changes over the time and under different environmental conditions.
This cheap type of sensor searches a relative "good air condition"-baseline by finding the "best air condition" in a longer interval and then assuming the sensor being in fresh unpolluted air at that time.
BUT: The sensor does not store this value by itself.

The sensor needs two conditions for giving reliable values:
  • a one-time burn-in-time of more than 48 hours
  • a minimum run-in of about 20minutes after each cold start.
Software:
The BASIC-Program was created with and runs in ANNEX32 - a BASIC interpreter for ESP32.. Minimum required version is V1.435 (Version without Bluetooth,, but with TELEGRAM-support)
  • The program measures the eCO2-level once per second..
  • The air eCO2 status gets categorized as GREEN, YELLOW or RED condition..
  • The build-in NeoPixel-Matrix locally indicates the condition by its color.
  • A Webinterface displays the eCO2-Value and the category in the (W)LAN..
IMG_0160.jpg
The Category and eCO2-value can be requested via TELEGRAM messenger as the program works as a TELEGRAM_BOT.
Additionally a TELEGRAM-Alert is send to the last TELEGRAM-chat_id, if condition is indicated as RED .

The baseline value can be stored manually by pressing the front button of the ATOM-module.

The Telegram-BOT will respond to this commands:
  • /e returns eCO2 value and category [GREEN,YELLOW,RED]
  • /s stores the baseline in /baseline.txt
  • /r restores the baseline from /baseline.txt
  • /i returns the local IP-settings of the module
  • [any other character] same as /e
telegram.png
Get Your own TELEGRAM_Token:
To use the TELEGRAM functions in the BASIC program you first have to create your own TELEGRAM-BOT by following the instructions of BotFather bot in your telegram APP. This will provide your personal TELEGRAM_TOKEN and a bot name for the BASIC-program code that can be inserted in the BASIC-code lines to set the appropriate variables
EB7D7CAB-4D64-49F4-8134-09111FAD9395.gif

The ANNEX32-BASIC code follows here for a better understanding of the functions.
It is also attached as a file eCO2_BOT.txt. . This file can be pasted into the editor of ANNEX32 and stored into the ESP32 module as an autorun-file in e.g. /default.bas

Code: [Local Link Removed for Guests]

'#######################################################################
' eCO2-Sensor
' ##################
'# Shows AIR QUALITY via the estimated concentration of carbon dioxide
'# calculated from known TVOC concentration. This is based on the
'# assumption that the VOC produced by humans is proportional to their exhaled CO2.
'
'# USED HARDWARE:
'  - ESP32-device best: M%Stack "ATOM lite" or "ATOM matrix" with buit-in NeoPixel(s)
'  - CCS811 eCO2-TVOC-Sensor at I2C-pins of the  ESP32
'  - switch-button (e.g. the front button of M5Stack ATOM)
'
'# OUTPUT of eCO2-ppm  via ...
'  - NEOPIXEL_LED with at least 1 pixel to indicate the range [GREEN|YELLOW|RED] of eCO2 ppm
'  - WebInterface to display eCO2-ppm  and Condition [GREEN|YELLOW|RED]
'  - TELEGRAM-BOT  message-on-demand with eCO2-ppm and Condition [GREEN|YELLOW|RED]
'  - TELEGRAM-BOT  alert message, if condition reaches RED eCO2-range for more than x measures values

'# Saves the  BASELINEof the CCS811 as "GOOD-AIR-CONDITION" in file /BASELINE.txt
'     if switch-button is pressed for more than 3 seconds

'# Sends a TELEGRAM Alert message to currentt CHAT_ID if RED-condition

'# TELEGRAM-BOT commands (with or without leading /) :
' /i => return local IP-Settings
' /s => store the current baseline representing "clean-air-condition"  in file  /baeline.txt
' /r => restore the baseline from file  /baeline.txt
' /e or [any other character] will return the  eCO2-ppm-value and the condition [GREEN|YELLOW|RED]

'#######################################################################
' Peter Neufeld 2021/09; DB9JG@me.com
Version$           = "V2.1"

'------SETTINGS-------------
RESTORE_BASELINE   = 1    '1 => after a run-in time: restores the  baseline from data file if available
SAVE_BASELINE      = 0    '1 => after a run-in time: save current air conditions as the "clean air" baseline
SILENT             = 0    '1 => suppress  all messages   0 => show some status-messages via  wlog
LOCATION$          = "ROOM 1"  'a description of the sensor location etc
TELEGRAM_activated = 1    '1 => activates the Telegram-BOT

TELEGRAM_TOKEN$             = "xxxxxxxxx:AAHQ3qTIj248QCU0ao_GcetggK3l_nhANj4"
TELEGRAM_BOTNAME$           = "@xxxxxxxx_eCO2_BOT"
TELEGRAM_MSG_Threshold      = 5 'Message if bad-air-condition for too long

TELEGRAM_MAX_FAILED_COUNTER = 0
TELEGRAM_MAX_FAILED         = 10
TELEGRAM_is_still_running   = 0

LL_GREEN   = 400   'lower limit of the range for the green LED;  usually ~400
LL_Yellow  = 1000  'lower limit of the range for the yellow LED; usually ~1000
LL_RED     = 1800  'lower limit of the range for the red LED;    usually ~1500
'---------------------------
eCO2       = 0
eTVOC      = 0
CONDITION$ = "GREEN"
CONDITION_OLD$ = CONDITION$
T$         = time$
STR_eCO2$  = ""
CHAT_ID$   = "484112878" 'me
CHAT_ID$   = ""

gosub SETUP_PERIPHERAL_HARDWARE
IF RESTORE_BASELINE = 1  then gosub CCS811_RESTORE_BL_FROM_FILE
gosub        MAKE_WEBPAGE
onhtmlreload MAKE_WEBPAGE
onHtmlChange MAKE_WEBPAGE
IF TELEGRAM_activated gosub TELEGRAM_INIT
timer0 1000, MAIN
wait
'####################################################################################
'####################################################################################
MAIN:
'-------------
gosub READ_CO2
gosub SHOW_CO2

T$        = time$
STR_eCO2$ = str$(eCO2)
if CONDITION$ <> CONDITION_OLD$ then gosub MAKE_WEBPAGE 'change the webpage

'===Send a telegram alert message to latest CHAT_ID if too many RED conditions-----
IF condition$ = "RED"  and CHAT_ID$ <>"" then
  RED_COUNT = RED_COUNT +1
else   'reset counter if good condition return before reaching threshold
  RED_COUNT = 0
endif
IF RED_COUNT = TELEGRAM_MSG_Threshold then gosub TELEGRAM_send_alert
'===-------------------------------------------------------------------------------

'++++restore the latest baseline regularly after a run-in time of 10 minutes
count=(count +1) mod (10*60)
'if count = (10*60)-1 then gosub CCS811_SAVE_BASELINE_TO_FILE
if count = (10*60)-1  gosub CCS811_RESTORE_BL_FROM_FILE
'++++--------------------------------------------------------
'''
'---SAVE baseline if frontbutton pressed longer
IF pin(FRONT_BUTTON) = PRESSED then
  PRESSED_COUNT = (PRESSED_COUNT + 1) mod 4
else
  PRESSED_COUNT = 0
ENDIF
IF PRESSED_COUNT = 3  gosub CCS811_SAVE_BASELINE_TO_FILE
'---

return

'####################################################################################
MAKE_WEBPAGE:
'-------------
cls
autorefresh 1000
'create the textbox in the html page
A$ = ""
A$ = A$ + "<H1>eCO2 " + LOCATION$
'A$ = A$ + VERSION$
A$ = A$ + "</H1>"
A$ = A$ + "Time :" + textbox$(T$) + "<br>"
A$ = A$ + "eCO2:" + textbox$(STR_eCO2$) + "<br>"
'A$ = A$ + "Cond :" + textbox$(CONDITION$) + "<br>"
A$ = A$ + |<span style="color:| + CONDITION$ + |">|
A$ = A$ + "<H1>Condition: "+ CONDITION$+ "</H1>"
A$ = A$ + "</span>"
html A$
return

'####################################################################################
SHOW_CO2:
'---------
x=5-x 'toggle the Brigthness   0 or 20
CONDITION_OLD$=CONDITION$
select case eCO2
  case 0 to  LL_YELLOW      'GREEN
    R=0 : G=x+20  : B=0
    CONDITION$ = "GREEN"
  case LL_YELLOW to LL_RED  'YELLOW
    R=x+10 : G=x+10 : B=0
    CONDITION$ = "YELLOW"
  CASE LL_RED to 99999      'RED
    R=x+20 : G=0 : B=0
    CONDITION$ = "RED"
end select

neo.strip 0, NEO_NUM, R,G,B
wlog "eCO2 = "; eCO2, "  Condition: "; CONDITION$
return

'####################################################################################
READ_CO2:
'---------
if ccs811.avail = 1 then
  a     = ccs811.read
  eCO2  = CCS811.CO2
  eTVOC = CCS811.TVOC
end if
return

'####################################################################################
SETUP_PERIPHERAL_HARDWARE:
'-------------------------
'I2C
i2c.setup 21, 22

'button to  inizialize a save-baseline-to-file
FRONT_BUTTON  = 39 'pin39 for build-in button of M5Stack ATOM xxxx
PRESSED       = 0  'switch pulls up at ATOM devices
PRESSED_COUNT = 0
pin.mode FRONT_BUTTON, input


'initialize the NEOPIXELs
NEO_PIN = 27     'NeoPixel data-pin for  M5stack "ATOM xxxx" devices
NEO_NUM = 1     ' Number of Neopixels for a M5stack "ATOM lite"
if bas.device = 103 then    '103 is a M5Stack "ATOM matrix"
  NEO_PIN = 27
  NEO_NUM = 25     'Number of Neopixels
endif
R=2 : G=2 : B=2  'initial colors for neopixel
neo.setup NEO_PIN, NEO_NUM
neo.strip 0,NEO_NUM,R,G,B

'CCS811 eCO2-Sensor
if ccs811.Setup(&h5a) <> 0 then
  print "CCS811 not found. Program stopped "
  wlog  "CCS811 not found. Program stopped "
  end                                     '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
endif
wlog ccs811.setdrivemode(1)  'update every second
return

'####################################################################################
CCS811_SAVE_BASELINE_TO_FILE:
'----------------------------
neo.strip 0,NEO_NUM,0,0,150   'Blue LED to indicate
BASELINE$ = str$(CCS811.GETBASELINE)
File.save "/BASELINE.txt", BASELINE$
wlog "Saved baseline ";BASELINE$ ; " to file /BASELINE.txt"
neo.strip 0,NEO_NUM,R,G,B     'Back to ald colors
return

'####################################################################################
CCS811_RESTORE_BL_FROM_FILE:
'---------------------------
BASELINE$  = "39103"  'default if no file
if file.exists("/BASELINE.txt") then
  BASELINE$ = File.read$("/BASELINE.txt")
  if val(BASELINE$) >0 then
    wlog "CCS811.SETBASELINE returned: "; CCS811.SETBASELINE(val(baseline$))
    wlog "Restored baseline ";BASELINE$ ; " from file /BASELINE1.txt"
  endif
endif
return

'####################################################################################
TELEGRAM_INIT:
'-------------
WLOG "TELEGRAM_INIT"
telegram.settoken TELEGRAM_TOKEN$
telegram.setwait  10
telegram.setmode  0
onwgetasync       TELEGRAM_asynco
'Get the update each 5 seconds
timer1 10000, TELEGRAM_getMessage
return

'####################################################################################
TELEGRAM_getMessage:
'-------------------
WLOG  time$;": TELEGRAM_getMessage:"
telegram.GetUpdatesAsync
return

'####################################################################################
TELEGRAM_send_alert:
'---------------
'send an ALERT message to latest telegram chat-id

if TELEGRAM_is_still_running then return
TELEGRAM_is_still_running = 1
onwgetasync   off   '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If CHAT_ID$="" then return

tt$ = "RED-ALERT condition  for " + LOCATION$ +" at "+ time$ + ": eCO2 = " + str_eCO2$  + "  Condition: " + CONDITION$

neo.strip 0,NEO_NUM,30,30,30   'white Neopixels to  indicate a TELEGRAM transmission
WLOG telegram.sendmessage$(val(CHAT_ID$),tt$ )
WLOG tt$
neo.strip 0,NEO_NUM,R,G,B      'back to former condition

TELEGRAM_is_still_running = 0
onwgetasync        TELEGRAM_asynco
return

'####################################################################################
TELEGRAM_asynco:
'---------------
'Receive the messages and respond according to included command-string

if TELEGRAM_is_still_running then return
TELEGRAM_is_still_running = 1
onwgetasync   off   '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
r$ = WGETRESULT$
WLOG "The TELEGRAM_BOT-Service  returns at  "; Time$; ": "; r$
if instr(lcase$(r$)," failed") then
  TELEGRAM_MAX_FAILED_COUNTER = TELEGRAM_MAX_FAILED_COUNTER + 1
  WLOG "The TELEGRAM_BOT-Service failed; REBOOT countdown initialized : ", str$(TELEGRAM_MAX_FAILED - TELEGRAM_MAX_FAILED_COUNTER)
  if TELEGRAM_MAX_FAILED_COUNTER = TELEGRAM_MAX_FAILED then
    WLOG "REBOOT NOW..."
    reboot
  endif
endif
if instr(r$,|"ok"|) then TELEGRAM_MAX_FAILED_COUNTER = 0
c$ = json$(r$, "chat.id")   'get the chat_id
if c$ <>"not found" then CHAT_ID$=c$

tt$ = LOCATION$ +" at "+ time$ + ": eCO2 = " + str_eCO2$  + "  Condition: " + CONDITION$

text$ = json$(r$, "text")
if (text$ <> "not found") then
  text$=replace$(text$,"/","") ' now the command may, but must not include a  leading /
  select case left$(lcase$(text$),1)
    case "i" : tt$=" Local IP-setting is " + IP$
    case "r"
      gosub CCS811_RESTORE_BL_FROM_FILE
      tt$="Restored the BASELINE from file"
    case "s"
      gosub CCS811_SAVE_BASELINE_TO_FILE
      tt$="Saved the BASELINE to file"
  end select
  neo.strip 0,NEO_NUM,30,30,30   'white Neopixels to  indicate a TELEGRAM transmission
  WLOG telegram.sendmessage$(val(CHAT_ID$),tt$ )
  neo.strip 0,NEO_NUM,R,G,B      'back to former condition
  
end if
TELEGRAM_is_still_running = 0
onwgetasync        TELEGRAM_asynco
return

'####################################################################################
IMG_0160.jpg
telegram.png
You do not have the required permissions to view the files attached to this post.
User avatar
Fernando Perez
Posts: 378
Joined: Mon Feb 15, 2021 10:09 pm
Location: Santander (Spain)
Has thanked: 195 times
Been thanked: 267 times

Re: ESP32 eCO2-Telegram-Bot

Post by Fernando Perez »

Peter, although now I am with other things and I am not going to build your project, I want to thank you for your publications.
I always keep their source codes to study their way of programming, which I have applied on several occasions.
And I love his designs on graph paper and freehand drawing. They remind me of good old days.
https://www.myrapidq.it/public/Mini-Notebook.pdf
User avatar
PeterN
Posts: 366
Joined: Mon Feb 08, 2021 7:56 pm
Location: Krefeld, Germany
Has thanked: 171 times
Been thanked: 203 times
Contact:

Re: ESP32 eCO2-Telegram-Bot

Post by PeterN »

Thank you Fernando!

Yes ... indeed - I also have one of those yellow Engineers notebooks in my bookshelf :-) Was often an almost inexhaustible source of good ideas! I have gladly adopted this style.
In the end I returned to hand drawing on electronic graph paper, as I put almost all my papers into an IPAD-pro with an iPencil :)
Hand drawing has never been easier!!!

Good luck!
Tymon Elektryk
Posts: 4
Joined: Mon Apr 19, 2021 4:24 pm
Been thanked: 2 times

Re: ESP32 eCO2-Telegram-Bot

Post by Tymon Elektryk »

Welcome
Please show me clear communication because this link does not work with ESP32
A $ = "https://api.telegram.org/botxxxxxxx:xxx ... text=Magda"

bs $ = WGET $ (A $)
wlog bs $
And it works from the browser
returns info No Data. httpCode: -1
User avatar
Electroguard
Posts: 836
Joined: Mon Feb 08, 2021 6:22 pm
Has thanked: 268 times
Been thanked: 317 times

Re: ESP32 eCO2-Telegram-Bot

Post by Electroguard »

Hi, haven't tried the code, but be aware that string variables need to end with $, so there should not be a space between the string variable name (letter "A" in this instance) and the dollar sign which denotes it as being a string variable A$
Tymon Elektryk
Posts: 4
Joined: Mon Apr 19, 2021 4:24 pm
Been thanked: 2 times

Re: ESP32 eCO2-Telegram-Bot

Post by Tymon Elektryk »

Hello
Thank you very much for your answer.
I have no problems with the syntax, google translator makes spaces.
I am having trouble reading the Version 1.43 help file.
The answer is in Version 1.43.4 where the command is

telegram.sendmessage$

Which explains everything and becomes simple
Post Reply