Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 15:16 26 Apr 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Armmite F4 Weather Station with ESP-01

Author Message
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3015
Posted: 10:20pm 18 Feb 2021
Copy link to clipboard 
Print this post

Inspired by lew247's rich pi-cromite weather station display (bottom of page 24) and Peter Mather's compass rose and ESP-01 wifi  efforts, I decided to make a version for the Armmite F4.

I signed up for an openweathermap.org account, downloaded the list of Cities, found the code for adjacent town of Liverpool, Nova Scotia, and after some fiddling on the PC was able to download the default data:

{"coord":{"lon":-64.7155,"lat":44.0335},"weather":[{"id":802,
"main":"Clouds","description":"scattered clouds","icon":"03d"}],
"base":"stations","main":{"temp":278.94,"feels_like":269.44,
"temp_min":278.71,"temp_max":279.15,"pressure":1008,"humidity":56},
"visibility":10000,"wind":{"speed":10.29,"deg":240,"gust":14.92},
"clouds":{"all":46},"dt":1612635812,"sys":{"type":1,"id":549,
"country":"CA","sunrise":1612611013,"sunset":1612647345},
"timezone":-14400,"id":6057856,"name":"Liverpool","cod":200}

From that I was able to work out how to extract the data. JSON$ is not available on the F4, so I wrote a very limited pseudo-json$ to pick out single values for single occurrences of a given key/name.

I hung a DS18B20 off of pin 1 for "inside temperature", and wanted to get the outside temperature from another device I have on my network. I figured out how the ESP-01 TCP GET was working for openweathermap, and set up my device to write the temperature within {} to a web server with a command like this on the openWrt device: echo '{-3}' > /www/oat.html

(If I had more than one value to provide from external sensors on my network, I'd put them out in pseudo-json$ format, e.g.: echo '{"oat":-3,"barnroom":18}' > /www/oat.html )

I read the DS18B20 with every program loop (there are no pauses except for processing for the ESP-01). If the temperature is dithering between one degree and another the display may change quite rapidly. I check the outside temperature once a minute. openweathermap.org says they won't allow you to retrieve your data more than once every 10 minutes, so I pick it up when minutes in time$ is at "00", "15", "30", "45". The seconds in the time display on the second line is updated every second except when the ESP-01 is working.

I pre-configured the ESP-01 to connect to my network on powerup (in AT mode, with the AT version 1.7 recently linked by matherp), so MMBasic code to do that is not included.

The standard 320x240 LCD is crisp, if small. Unfortunately, I can't get a good picture of it--tried both phone and camera.




Dim integer lblue=RGB(172,209,255),grey=rgb(192,192,192),i,j,k,l,m,n
Dim integer EspFlag=1,iconFlag=1,firstPassFlag=1,txtFont=1,ESPOKFlag%
Dim integer ls%(1000),nNames=10,degrees, x_endpoint, y_endpoint
Dim integer outsideTemp=-2, insideTemp=21, OldOutsideTemp, OldInsideTemp
'Dim cx% = 225, cy% = 100, wid% = 50
Dim cx% = mm.hres*.75-5, cy% = (mm.vres-40)/2+20, wid% = mm.hres/6
Dim ang! = 0.087266463, rad90! = 1.570796327  '90 degrees in radians
Dim string a$,b$,c$,d$,e$,http$,minute$,second$,item$,Values(10) length 20
Dim string names$(10) length 15
names(0)="description":names(1)="temp":names(2)="pressure":names(3)="humidity"
names(4)="speed":names(5)="deg":names(6)="gust":names(7)="country":names(8)="name"
names(9)="icon"
Dim string labels$(10) length 25
labels$(0)="Sky": labels$(1)="Temperature": labels$(2)="Atmospheric Pressure"
labels$(3)="Humidity": labels$(4)="Wind Speed": labels$(5)="From the"
labels$(6)="Gusting to": labels$(7)="City": labels$(8)=","
Dim string points$(16) length 3  =("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","","")
points(15)="NNW": points(16)="N"
dim string iconCodes$="01d02d03d04d09d10d11d13d50d"
dim integer pESP_RST=98: pin(pESP_RST)=0: setpin pESP_RST,DOUT ' set up ESP-01 Reset pin low
dim integer pInTemp=1,iFailedCnt,iEspStage,wOrgFailedFlag=1

Dim MYID$="6057856" ' Liverpool, Nova Scotia
Dim APIKEY$="YourKeyGoesHere"
Dim report$="weather", URL$="api.openweathermap.org"
http$= "GET /data/2.5/"+report$+"?id="+MYID$+"&APPID="+APIKEY$
http$=http$+" HTTP/1.0"+Chr$(13)+Chr$(10)+Chr$(13)+Chr$(10)
Dim string LOCALURL$="192.168.2.65"
Dim string LOCALGET$= "GET /oat.html HTTP/1.0"+Chr$(13)+Chr$(10)+Chr$(13)+Chr$(10)

if iconFlag then: geticons: endif
open "com2:115200,8192" as #1

if mm.hres=320 then: txtFont=7: endif
box 0,0,mm.hres,40,,rgb(white),grey
box 0,40,mm.hres/2,mm.vres-40,2,rgb(white),lblue
box mm.hres/2+1,40,mm.hres/2,mm.vres-40,2,rgb(white),lblue
text mm.hres/2,5,"Weather: Milton, Nova Scotia",C,1,,rgb(white),grey
text mm.hres/2,20,date$+" "+time$,C,1,,rgb(white),grey
compass_rose cx%,cy%,wid%
getWeather
writeScreen
getOAT
a$=mid$(time$,4,2) ' get minutes
i=val(a$) mod 15
if i < 5 then: firstPassFlag=0: endif ' GET won't violate 10 minute rule

restart:

do
 a$=mid$(time$,7,2) ' get second
 if second$<>a$ then
   text mm.hres/2,20,date$+" "+time$,C,1,,rgb(white),grey
   second$=a$
   a$=mid$(time$,4,2) ' get minute
   if minute$<>a$ then
     minute$=a$
     if wOrgFailedFlag or minute="00" or minute="15" or minute="30" or minute="45" then ' get weather
       if firstPassFlag then
         firstPassFlag=0 ' don't violate "no more than once every 10 minutes" rule
       else
         getWeather
         writeScreen
       endif
     endif
     getOAT
   endif
 endif
 i=tempr(pInTemp): if i<>1000 then: insideTemp=i: endif
 if oldInsideTemp<>insideTemp then
   oldInsideTemp=insideTemp
   text mm.hres/2+13,mm.vres*.80,"INSIDE",,txtFont,,rgb(black),lblue
   text mm.hres/2+10,mm.vres*.85,str$(insideTemp)+"C",,5,,rgb(gray),lblue
   logTmp
 endif
 if oldOutsideTemp<>outsideTemp then
   oldOutsideTemp=outsideTemp
   text mm.hres-65,mm.vres*.80,"OUTSIDE",,txtFont,,rgb(black),lblue
   text mm.hres-70,mm.vres*.85,str$(outsideTemp),,5,,rgb(gray),lblue
 endif
loop

sub writeScreen
 x=10:y=45:
 for i=0 to 6
   if i=2 then
     text x,y,labels$(i)+": ",,txtFont,,rgb(black),lblue:y=y+15:
     text x,y,"  "+Values$(i),,txtFont,,rgb(black),lblue:y=y+15:
   else
     text x,y,labels$(i)+": "+Values$(i),,txtFont,,rgb(black),lblue):y=y+15:
   endif
 next i
 circle cx%,cy%,wid%-6,,,lblue,lblue
 circle cx%,cy%,wid%/8,,,rgb(red),rgb(red) ' center
 n=((630-degrees) mod 360) ' opposite of direction of wind
 text x,215,"Wind to "+str$(n),,txtFont,,rgb(black),lblue
 n=((degrees+180) mod 360) ' opposite of direction of wind
 for i=-3 to 3 ' lines offset from center (cx%) to make arrow
   x_endpoint=(cx%)+(Cos(n/5*ang!)*(wid%-8)) ' ang! = 0.087266463 (5 degrees)
   y_endpoint=(cy%)-(Sin(n/5*ang!)*(wid%-8))
   Line (cx%+i),(cy%+i),x_endpoint,y_endpoint,,RGB(RED)
   Line (cx%-i),(cy%-i),x_endpoint,y_endpoint,,RGB(RED)
'  Line (cx%+i),(cy%+i),(cx%)+(Cos(n*ang!)*(wid%-8)),(cy%)-(Sin(n*ang!)*(wid%-8)),,RGB(RED)
 next i
'  text x,200,"Condition: ",,txtFont,,rgb(black),lblue
 text x,200,"Condition:  "+Values(9),,txtFont,,rgb(black),lblue
 iconFlag=0
 for i=0 to 8 ' check icon availability
   a$=mid$(iconCodes$,i*3+1,3)
'    print a$+"="+Values(9)+"? ";
   if a$=Values$(9) then: iconFlag=i+1: exit for: endif
 next i
 if iconFlag then
   blit write iconFlag,mm.hres/4,180,50,50
 else
   text x+10,212,Values$(0),,txtFont,,rgb(black),lblue
 endif
end sub

sub compass_rose cx%,cy%,wid%
Local a%
Text cx%-6,cy%-wid%-17),"N",L,1,,RGB(1,1,1),lblue
Text cx%-6,cy%+wid%+5,"S",L,1,,RGB(1,1,1),lblue
Text cx%+wid%+5,cy%-11,"E",L,1,,RGB(1,1,1),lblue
Text cx%-(wid%)-10,cy%-11,"W",L,1,,RGB(1,1,1),lblue
if a%<>a% then
Text 10,10,"NE",L,7,,RGB(1,1,1),RGB(134,174,230)
Image rotate 6,4,30,30,cx%+(wid%-16)*Cos(.785),cy%-(wid%-16)*Cos(.785),45,1
Text 10,10,"SE",L,7,,RGB(1,1,1),RGB(134,174,230)
Image rotate 6,4,30,30,cx%+(wid%-16)*Cos(.785),cy%+(wid%-16)*Cos(.785),135,1
Text 10,10,"SW",L,7,,RGB(1,1,1),RGB(134,174,230)
Image rotate 6,4,30,30,cx%-(wid%-16)*Cos(.785),cy%+(wid%-16)*Cos(.785),225,1
Text 10,10,"NW",L,7,,RGB(1,1,1),RGB(134,174,230)
Image rotate 6,4,29,29,cx%-(wid%-16)*Cos(.785),cy%-(wid%-16)*Cos(.785),315,1
Text 10,10,"  ",L,7,,RGB(134,174,230),RGB(134,174,230) ' clear text
' tick marks, every 5 degrees (360/5 = 72)
endif
For a% = 0 To 71 ' note: for angles, East is zero
 Line (cx%)+(Cos(a%*ang!)*(wid%-4)),(cy%)-(Sin(a%*ang!)*(wid%-4)),(cx%)+(Cos(a%*ang!)*(wid%+1)),(cy%)-(Sin(a%*ang!)*(wid%+1)),,RGB(WHITE)
Next
' COMPASS perimiter
Circle cx%,cy%,wid%
Circle cx%,cy%,wid%-4
circle cx%,cy%,wid%/8,,,rgb(red),rgb(red) ' center
End Sub

Sub getWeather
if EspFlag then:
 getWeatherOrg
'  print "Skipping getWeatherOrg"
else
 Open "livr.jsn" For input As #2
 Do While Not Eof(2)
   Line Input #2, a$: ' Print a$
   LongString append ls%(),a$
 Loop
 Close #2
 ' LongString print ls%(): Print
endif

 For n=0 To nNames-1
   item$=names$(n)
   Values$(n)=pseudo_json$(ls%(),item$)
'    Print item$,Values$(n)
   If item$="temp" Then: Values$(n)=Str$(Val(Values$(n))-273.15,0,1)+"C": EndIf
   If item$="deg" Then
     degrees=Val(Values$(n))
'      i=(degrees+11.25)/22.5
     i=((450-degrees+11.25) mod 360)/22.5
     Values$(n)=points$(i)
'      print item$,degrees,i,Values$(n)
   EndIf
   If item$="humidity" Then: Values$(n)=Values$(n)+"%": EndIf
   If item$="speed" Then: Values$(n)=Values$(n)+"kph": EndIf
   If item$="pressure" Then: Values$(n)=Values$(n)+" millibars": EndIf
   If item$="gust" Then: Values$(n)=Values$(n)+"kph": EndIf
 Next n
End Sub

Function pseudo_json$(ls%(),key$)
 local integer i,j,k,l,m
 local string a,b
 m=1
 pseudo_json$=""
 Do
   i=LInStr(ls%(),key$,m)
'    Print key$,i
   If i Then
     a=LGetStr$(ls%(),i-1,1)
     b=LGetStr$(ls%(),i+Len(key$),1)
'      Print "|";a;"|","|";b;"|";
     If a=Chr$(34) And b=Chr$(34) Then ' found the key
       j=LInStr(ls%(),",",i+Len(key$)+2)
       If j>0 Then
         k=i+Len(key$)+2
         a=LGetStr$(ls%(),k,j-k)
'          Print a
         If Mid$(a,1,1)=Chr$(34) Then ' remove "s
           a=Mid$(a,2,Len(a)-2)
         EndIf
         If Instr(a,"}") Then: a=Mid$(a,1,Len(a)-1): EndIf ' strip "}"
         If mid$(a,len(a),1) = chr$(34) Then: a=Mid$(a,1,Len(a)-1): EndIf ' strip double-quote
         pseudo_json$=a
         Exit Do
       EndIf
     EndIf
     m=i+Len(key$)
   Else
     Exit Do ' key not found    
   EndIf
 Loop
End Function

sub geticons
local integer i,j,k,x,y
Load image "icons.bmp"
'for i=1 to 9: on error skip: blit close i: next i
k=1:x=0
for i=1 to 3
 y=0
 for j=1 to 3
   blit read k,x,y,50,50: y=y+50:k=k+1
 next j
 x=x+50: y=0
next i
end sub

Sub getWeatherOrg
LongString clear ls%()
wOrgFailedFlag=1
ESPInit
if MYID$<>MYID$ then ' skip old initialization
 pause 8000
 print #1,"AT+CIPSNTPCFG=1,-4,"+chr$(34)+"us.pool.ntp.org"+chr$(34)+chr$(13)+chr$(10);
 if NOT OKwait(5000) then errorexit("AT+CIPSNTPCFG")
 print #1,"AT+CIPSNTPTIME?"+chr$(13)+chr$(10);
 print "Time: ": pause 2000
 do while loc(1)>0: print input$(1,1);: loop: print
 print "RTC Date/Time: "+date$+" "+time$

 print #1,"AT+CWMODE_CUR=1"+chr$(13)+chr$(10);
 if NOT OKwait(4000) then errorexit("AT+CWMODE_CUR=1")
 print #1,"AT+CWJAP_CUR="+chr$(34)+"Omnibus_N"+chr$(34)+","+chr$(34)+"amber1977"+chr$(34)+chr$(13)+chr$(10);
 if NOT OKwait(10000) then errorexit("AT+CWJAP_CUR=")
endif

 iEspStage=iEspStage+1
print #1,"AT+CIPSTART="+chr$(34)+"TCP"+chr$(34)+","+chr$(34)+URL$+chr$(34)+",80"+chr$(13)+chr$(10);
if NOT OKwait(10000) then errorexit("AT+CIPSTART=")
 iEspStage=iEspStage+1
print #1,"AT+CIPMODE=1"+chr$(13)+chr$(10);
if NOT OKwait(4000) then errorexit("AT+CIPMODE=1")

'do: loop
 iEspStage=iEspStage+1
print "Trying: "+http$
print #1,"AT+CIPSEND"+chr$(13)+chr$(10);
if NOT OKwait(4000) then errorexit("AT+CIPSEND")
print #1,http$;
getinput(10000)
print "Returned: ";
longstring print ls%() ' lb

a$=lgetstr$(ls%(),1,1)
if a$="{" then
 wOrgFailedFlag=0
 on error skip 4
 open "weather.log" for append as #3
 print #3, mid$(date$,9,2)+mid$(date$,4,2)+mid$(date$,1,2)+mid$(time$,1,2)+mid$(time$,4,2)+mid$(time$,7,2)
 longstring print #3, %ls()
 close #3
endif
print #1,"+++";
pause 1000
 iEspStage=iEspStage+1
print #1,"AT+CIPMODE=0"+chr$(13)+chr$(10);
if NOT OKwait(4000) then errorexit("AT+CIPMODE=0")
 iEspStage=iEspStage+1
print #1,"AT+CIPCLOSE"+chr$(13)+chr$(10);
if NOT OKwait(4000) then errorexit("AT+CIPCLOSE")
'do:loop
end sub

function OKwait(timeout as integer) as integer
OKwait=1
timer=0
do
loop until input$(1,1)="O" or timer>=timeout
do
loop until input$(1,1)="K" or timer>=timeout
if timer>=timeout then OKwait=0
end function

sub errorexit(calling as string)
print "AT call timeout from - ",calling
print #1,"AT+CIPCLOSE"+chr$(13)+chr$(10)
iFailedCnt=iFailedCnt+1
if iFailedCnt > 5 then: end: : endif
'goto restart

end sub

sub getinput(waitpause as integer)
local a$
local j%,i%=-1
timer=0
do
a$=input$(1,1)
If a$<>"" Then
 LongString append ls%(),a$
'   print a$;
 if a$="{" then
   if i%=-1 then
     i%=1
   else
     i%=i%+1
   endif
 endif
 if a$="}" then i%=i%-1
endif
loop while timer<=waitpause and i%<>0
j%=LInStr(ls%(),"{")
' print "TCP: ";j%;" ";: longstring print ls%()
if j%>0 then: LongString trim ls%(),j%-1: endif
'print ""
end sub

sub ESPInit
 iEspStage=1
 ESPOKFlag%=0
 for i=1 to 5
   print "AT+";
   print #1,"AT"+chr$(13)+chr$(10);
   if OKwait(5000) then: ESPOKFlag%=1: exit for: endif
   pin(pESP_RST)=0: pause 1000: pin(pESP_RST)=1: pause 2000 ' toggle reset pin
 next i
 if not ESPOKFlag% then
   for i=1 to 5
     print "RST ";
     print #1,"RST"+chr$(13)+chr$(10);
     pause 5000
     print #1,"AT"+chr$(13)+chr$(10);
     if OKwait(5000) then: ESPOKFlag%=1: exit for: endif
   next i
 endif
end sub

sub getOAT ' Outside Air Temperature (html get)
 longstring clear ls%()
 print "OAT: ESPinit: ";
 ESPInit
 iEspStage=iEspStage+1
 a$="AT+CIPSTART="+chr$(34)+"TCP"+chr$(34)+","+chr$(34)+LOCALURL$+chr$(34)+",80"
 print a$
 print #1,a$+chr$(13)+chr$(10);
 if NOT OKwait(10000) then errorexit("OAT: AT+CIPSTART=")
 iEspStage=iEspStage+1
 print #1,"AT+CIPMODE=1"+chr$(13)+chr$(10);
 if NOT OKwait(4000) then errorexit("OAT: AT+CIPMODE=1")

 print "Trying: "+mid$(LOCALGET$,1,len(LOCALGET$)-4)+": ";
 iEspStage=iEspStage+1
 print #1,"AT+CIPSEND"+chr$(13)+chr$(10);
 if NOT OKwait(4000) then errorexit("OAT: AT+CIPSEND")
 print #1,LOCALGET$;
 getinput(10000)
'  print "Local Return: ";
'  longstring print ls%() ' lb
 a$=lgetstr$(ls%(),2,10) ' more characters than valid
 i=val(a$)
 if i>-40 and i < 50 then
   print i
   if i<>outsideTemp then
     outsideTemp=i
     logTmp
   endif
 else
   print
 endif

 print #1,"+++";
 pause 1000
 iEspStage=iEspStage+1
 print #1,"AT+CIPMODE=0"+chr$(13)+chr$(10);
 if NOT OKwait(4000) then errorexit("OAT: AT+CIPMODE=0")
 iEspStage=iEspStage+1
 print #1,"AT+CIPCLOSE"+chr$(13)+chr$(10);
 if NOT OKwait(4000) then errorexit("OAT: AT+CIPCLOSE")
end sub

sub logTmp
 on error skip 4
 open "wtemp.log" for append as #3
 a$=mid$(date$,9,2)+mid$(date$,4,2)+mid$(date$,1,2)+mid$(time$,1,2)+mid$(time$,4,2)+mid$(time$,7,2)
 print #3,"T "+str$(insideTemp)+" "+str$(outsideTemp)+" ~ "+a$
 close #3
 i=0 ' null
end sub

Edited 2021-02-19 08:27 by lizby
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
Chopperp

Guru

Joined: 03/01/2018
Location: Australia
Posts: 1032
Posted: 10:35pm 18 Feb 2021
Copy link to clipboard 
Print this post

All I can say is "Wow"

  lizby said  The standard 320x240 LCD is crisp, if small. Unfortunately, I can't get a good picture of it--tried both phone and camera.

I find SAVE IMAGE File$ works well.
ChopperP
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3015
Posted: 10:47pm 18 Feb 2021
Copy link to clipboard 
Print this post

  Chopperp said  SAVE IMAGE File$ works well.


Perfect, thank you.



Edited 2021-02-19 08:57 by lizby
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024