Sensor network over ethernet W5500

Place your projects here
Post Reply
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

Sensor network over ethernet W5500

Post by Fernando Perez »

I am installing in the home of an elderly person who lives alone, a network of ESP8266 sensors linked by ESPNOW to an ESP32 base station that accesses the Internet only by Ethernet W5500, not by Wifi. In fact, the Wifi access point of the home router is not used at all.
image.png
The sensors, one for each room, detect:
  • By means of a module RCWL0516 the movement.
    By means of a DHT11 module, the temperature and humidity of the room.
    By means of an LDR resistor, the level of illumination.
Finally, the reed relay of a standard door opening sensor controls the entrance and exit of the house.
Each time the motion sensor in the room is activated, it sends a message to the base station, which records the room number, the type of event and its value and adds the date and time it occurred.
With the periodicity that we establish, we check if the temperature, humidity and / or light level have varied, within adjustable limits, and send the corresponding message.

The first stumbling block I found is that, in its current state, the implementation of the W5500 module in Annex does not allow to use NTP synchronization, nor to upload the results to an external server using FTP, nor to send eMails.
But everything has a solution: ETHERNET.WGET$ works perfectly and I have used it to obtain our public IP, synchronize the current date / time and upload the collected data to the thingspeak.com server.

I should point out that this entire system is, in fact, a manifest intrusion into the private lives of our loved ones, but in today's sad circumstances of forced estrangement and loneliness, it can be vital in detecting bouts of depression or symptoms of physical illness prematurely through the statistical study of their daily habits and customs.

How to do it:
We recorded the ESP32 with the option "Flash firmware only". We connect to it through the address 192.168.4.1 and leave the entire configuration page blank, except for the name of the access point, the “Autorun file” and the username and password of the “Protected acces”, since the station will be visible to our neighbors:
image.png

We connect the W5500 module:
image.png
And we load the program ethernet_min.bas

Code: [Local Link Removed for Guests]

' *************************
' ** EspNow and Ethernet **
' **    V0.0 14/04/21    **
' *************************
' Write API key of our account in thingspeak.com
API_KEY$ = "xxxxxxxxxxxxxxxx"

' pin scs of W5500 to pin GPIO15 of ESP32
Ethernet 15, "http://www.vermiip.es/vermiip/muestraip.php"

' time offset from our country = 2
NTP 2, "http://free.timeanddate.com/clock/i7q6n1qi/n1440/tles4/tt0/tw0/tm3/td2/th1/tb1"

' turn on the network
ok = espnow.begin 
if ok = 0 then wlog "Mode ESPNOW active" else wlog "Fail ESPNOW activate"
onEspNowMsg message

wait 
END

' ---------------------------------------------------------------  
message:
' message struct: room number, event type, value
' event type: (M)otion, (T)emperature, (H)umidity, (L)ight
  message$ = espnow.read$
  room$ = word$(message$, 1, ","))
  event$ = word$(message$, 2, ",")
  value$ = word$(message$, 3, ",")
  thingspeak room$, event$, value$ 
return

' ---------------------
SUB Ethernet(scs, url$)
' ---------------------
LOCAL ok, a$
  ok = ethernet.init(scs) ' SCS W5500 to GPIO15
  if ok < 1 then END

  a$ = ethernet.IP$
  wlog "IP: " + word$(a$,1)
  wlog "Mask: " + word$(a$,2)
  wlog "Gateway: " + word$(a$,3)
  a$ = ethernet.wget$(url$)
  wlog "Public IP: " + word.extract$(a$, "<strong>", "</strong>")
END SUB

' -------------------
SUB NTP(offset, url$)
' -------------------
LOCAL t$
LOCAL year, month, day, hour, minute, second
  t$ = ethernet.wget$(url$)
  t$ = word.extract$(t$, "<span id=t1>", "</span>")
  wlog t$
  year = val(mid$(t$, 9, 2))
  month = val(mid$(t$, 4, 2))
  day = val(mid$(t$, 1, 2))
  hour = val(mid$(t$,13, 2)) + offset
  minute = val(mid$(t$, 16,2))
  second = val(mid$(t$, 19, 2)) 
  SETTIME year, month, day, hour, minute, second
  wlog date$, time$
END SUB

' -----------------------------------
SUB thingspeak(room$, event$, value$)
' -----------------------------------
LOCAL g$
  g$ = "api.thingspeak.com/update?api_key=" + API_KEY$
  g$ = g$ + "&field1=" + room$
  g$ = g$ + "&field2=" + event$
  g$ = g$ + "&field3=" + value$
  g$ = g$ + "&field4=" + date$
  g$ = g$ + "&field5=" + time$
  wlog ethernet.wget$(g$, 80)
END SUB
We recorded each of the ESP8266s with the option “Flash firmware only”. We connect to it through the address 192.168.4.1 and fill in the configuration page according to this image, taking care to vary the name and IP for each ESP8266:
image.png
And we load the sensor.bas program

Code: [Local Link Removed for Guests]

' *********************
' **  EspNow Sensors **
' **  V1.0 14/04/21  **
' *********************
' event type: (M)otion, (T)emperature, (H)umidity, (L)ight
' message structure: room,event,value 
' last measure:
Tprev = 0 : Hprev = 0 :Lprev = 0

Id$ = "0"  ' identifier of this unit
message$ = ""

' start network espnow
rMAC$ = "CC:50:E3:92:5E:41" ' address of the receiver
ok = espnow.begin 
if ok = 0 then wlog "ESPNOW ON" else wlog "ESPNOW FAIL"
espnow.add_peer rMAC$ 
onEspNowError status

' motion sensor RCWL0516
pin.mode 12, input
interrupt 12, RCWL0516

' temperature/humidity sensor DHT11
DHT.SETUP 2, 11
timer0 30000, sampling ' sample sensors every 30 seconds
wait
END

' ----------------------
sendmessage:
  espnow.write(message$, rMAC$)
  wlog message$
return

' ----------------------
status:
  wlog "TX error on "; espnow.error$ ' print the error
return

' ----------------------
RCWL0516:
  if pin(12) = 0 then return
  message$ = Id$ + ",M,1" ' Motion detected
  gosub sendmessage 
return

' ----------------------
sampling:
  T = DHT.TEMP
  if (T<=(Tprev-1)) OR (T>=(Tprev+1)) then
    message$ = Id$ + ",T," + str$(T) ' send temperature
    gosub sendmessage
    Tprev = T
  end if

  H = DHT.HUM
  if (H<=(Hprev-5)) OR (H>=(Hprev+5)) then
    message$ = Id$ + ",H," + str$(H) ' send humidity
    gosub sendmessage
    Hprev = H
  end if

  L = ADC
  if (L<=(Lprev-20)) OR (L>=(Lprev+20)) then
    message$ = Id$ + ",L," + str$(cint(L)) ' send brightness
    gosub sendmessage
    Lprev = L
  end if
return
So far so good, but I could not refuse the temptation to "beautify" and expand the application, so that the information provided by the sensors can be seen on a floor plan. Something absurd, since the only thing that interested me was to collect the information in thingspeak for its statistical treatment.
But we all know that since 1990 more attention has been paid to the visual aesthetics of the application than to its content ...
The result is this:

Code: [Local Link Removed for Guests]

' *************************
' ** EspNow and Ethernet **
' **    V1.0 14/04/21    **
' *************************
' Write API key of our account in thingspeak.com
API_KEY$ = "xxxxxxxxxxxxxxxx"

'  message type: (M)otion, (T)emperature, (H)umidity, (L)ight 
DIM type$(3) = "M", "T", "H", "L"
 
' rooms of the house:
DIM room$(5) = "cocina", "salon", "servicio", "invitados", "bano", "dormitorio"
lastRoom = 0 ' Where was the last time?

' pin scs of W5500 to pin GPIO15 of ESP32
Ethernet 15, "http://www.vermiip.es/vermiip/muestraip.php"

' time offset from our country = 2
NTP 2, "http://free.timeanddate.com/clock/i7q6n1qi/n1440/tles4/tt0/tw0/tm3/td2/th1/tb1"

' start log file
file$ = "" : line$ = "Connect at " + time$ + " " + date$
dailyLog line$

' turn on the network
ok = espnow.begin 
if ok = 0 then wlog "Mode ESPNOW active" else wlog "Fail ESPNOW activate"
onEspNowMsg message

onhtmlreload plano
gosub plano

'timer0 1000, simulacrum  ' comment in final version
wait 
END

' ---------------------------------------------------------------  
message:
  message$ = espnow.read$
  wlog message$
  gosub update
  
  line$ = message$ + "," + time$ + "," + date$
  dailyLog line$
  wlog line$
  
'  thingspeak room, event$, value$ 
   
return

' ---------------------------------------------------------------  
update:
' message struct: room number, event type, value
  room = val(word$(message$, 1, ","))
  event$ = word$(message$, 2, ",")
  value$ = word$(message$, 3, ",")

  select case event$
    case "M"  ' Motion
      css cssId$(room$(lastRoom),"fill:white; stroke:white;")
      css cssId$(room$(room), "fill:#ffffaa; stroke:#ff7f00; stroke-width:5;")
      lastRoom = room
    case "T"  ' Temperature
      value$ = value$ + "º"
    case "H"  ' Humidity
      value$ = value$ + "%"
    case "L"  ' Light
      value$ = value$ + " lx"
  end select

  if event$ <> "M" then
    j$ = "document.getElementById('" + event$ + str$(room) + "').textContent = '" + value$ + "';"
    wlog j$
    jscall j$
  end if
    
return

' ---------------------------------------------------------------  
simulacrum:
  message$ = str$(rnd(6)) + "," + type$(rnd(4)) + "," + str$(rnd(100))
  wlog message$
  gosub update
return

' ---------------------
SUB Ethernet(scs, url$)
' ---------------------
LOCAL ok, a$
  ok = ethernet.init(scs) ' SCS W5500 to GPIO15
  select case ok
    case 0  : wlog "Failed to receive a DHCP IP"
    case 1  : wlog "DHCP IP received successfully"
    case 2  : wlog "Using a manually configured fixed IP address"
    case -1 : wlog "Ethernet module not found"
    case -2 : wlog "UTP cable is not connected"
  end select
  if ok < 1 then END

  a$ = ethernet.IP$
  wlog "IP: " + word$(a$,1)
  wlog "Mask: " + word$(a$,2)
  wlog "Gateway: " + word$(a$,3)
  a$ = ethernet.wget$(url$)
  wlog "Public IP: " + word.extract$(a$, "<strong>", "</strong>")
END SUB

' -------------------
SUB NTP(offset, url$)
' -------------------
LOCAL t$
LOCAL year, month, day, hour, minute, second
  t$ = ethernet.wget$(url$)
  t$ = word.extract$(t$, "<span id=t1>", "</span>")
  wlog t$
  year = val(mid$(t$, 9, 2))
  month = val(mid$(t$, 4, 2))
  day = val(mid$(t$, 1, 2))
  hour = val(mid$(t$,13, 2)) + offset
  minute = val(mid$(t$, 16,2))
  second = val(mid$(t$, 19, 2)) 
  SETTIME year, month, day, hour, minute, second
  wlog date$, time$
END SUB

' -----------------
SUB dailyLog(line$)
' -----------------
  file$ = "/dat" + right$(date$, 2) + mid$(date$, 4, 2) + left$(date$, 2) + ".txt"
  line$ = line$ + chr$(13)
  if file.exists(file$) then
    file.append file$, line$
  else
    file.save file$, line$
  end if
END SUB

' ----------------------------------
SUB thingspeak(room, event$, value$)
' ----------------------------------
LOCAL g$
g$ = "api.thingspeak.com/update?api_key=" + API_KEY$
g$ = g$ + "&field1=" + str$(room) + "&field2=" + event$ + "&field3=" + value$
g$ = g$ + "&field4=" + date$ + "&field5=" + time$
wlog ethernet.wget$(g$, 80)
END SUB

' -------------------------------------------------------------------------------------
plano:
cls
a$ = ""
a$ = a$ + |<center>|
a$ = a$ + |<svg width="768" height="747">|
' <!-- Walls -->
a$ = a$ + |<g style="fill:#666666;">|
a$ = a$ + |<rect x="8" y="5" width="8" height="372"/>|
a$ = a$ + |<rect x="8" y="418" width="8" height="142"/>|
a$ = a$ + |<rect x="8" y="652" width="8" height="84"/>|
a$ = a$ + |<rect x="16" y="728" width="386" height="8"/>|
a$ = a$ + |<rect x="394" y="580" width="8" height="148"/>|
a$ = a$ + |<rect x="394" y="572" width="25" height="8"/>|
a$ = a$ + |<rect x="472" y="572" width="21" height="8"/>|
a$ = a$ + |<rect x="485" y="443" width="8" height="129"/>|
a$ = a$ + |<rect x="492" y="443" width="265" height="8"/>|
a$ = a$ + |<rect x="749" y="49" width="8" height="394"/>|
a$ = a$ + |<rect x="698" y="49" width="53" height="8"/>|
a$ = a$ + |<rect x="512" y="49" width="115" height="8"/>|
a$ = a$ + |<rect x="247" y="49" width="57" height="8"/>|
a$ = a$ + |<rect x="201" y="45" width="47" height="8" transform="rotate(11 225 48)"/>|
a$ = a$ + |<rect x="14" y="9" width="47" height="8" transform="rotate(11 37 14)"/></g>|
' <!-- Windows -->
a$ = a$ + |<g style="fill:#aaffff; stroke:#b2b2b2; stroke-width:2;">|
a$ = a$ + |<rect x="8" y="561" width="8" height="90"/>|
a$ = a$ + |<rect x="8" y="378" width="8" height="40"/>|
a$ = a$ + |<rect x="59" y="29" width="144" height="8" transform="rotate(11 140 29)"/>|
a$ = a$ + |<rect x="303" y="48" width="208" height="8"/>|
a$ = a$ + |<rect x="628" y="48" width="69" height="8"/></g>|
' <!-- Sliding door -->
a$ = a$ + |<rect x="632" y="171" width="70" height="8" fill="#aaffff" stroke="#b2b2b2" stroke-width="2" />|
a$ = a$ + |<line x1="615" x2="676" y1="170" y2="170" stroke="#0000ff" stroke-width="3"/>|
a$ = a$ + |<line x1="592" x2="644" y1="180" y2="180" stroke="#0000ff" stroke-width="3"/>|
' <!-- Doors -->
a$ = a$ + |<g style="fill:none; stroke:#cccccc;">|
a$ = a$ + |<rect x="420" y="571" width="51" height="9" id="front_door"/>|
a$ = a$ + |<rect x="485" y="382" width="8" height="50"/>|
a$ = a$ + |<rect x="376" y="355" width="104" height="8" />|
a$ = a$ + |<rect x="362" y="370" width="8" height="50"/>|
a$ = a$ + |<rect x="180" y="355" width="50" height="8" />|
a$ = a$ + |<rect x="171" y="426" width="50" height="8" />|
a$ = a$ + |<rect x="154" y="370" width="8" height="50"/>|
a$ = a$ + |<rect x="296" y="533" width="50" height="8" /></g>|
' <!-- Interior walls -->
a$ = a$ + |<g style="stroke:#56ffaa; stroke-width:8;">|
a$ = a$ + |<line x1="245" y1="57"  x2="245" y2="356"/>|
a$ = a$ + |<line x1="588" y1="57"  x2="588" y2="356"/>|
a$ = a$ + |<line x1="592" y1="175" x2="630" y2="175"/>|
a$ = a$ + |<line x1="704" y1="175" x2="749" y2="175"/>|
a$ = a$ + |<line x1="16"  y1="359" x2="178" y2="359"/>|
a$ = a$ + |<line x1="233" y1="359" x2="374" y2="359"/>|
a$ = a$ + |<line x1="482" y1="359" x2="592" y2="359"/>|
a$ = a$ + |<line x1="158" y1="363" x2="158" y2="369"/>|
a$ = a$ + |<line x1="366" y1="363" x2="366" y2="369"/>|
a$ = a$ + |<line x1="490" y1="363" x2="490" y2="380"/>|
a$ = a$ + |<line x1="158" y1="421" x2="158" y2="502"/>|
a$ = a$ + |<line x1="162" y1="430" x2="170" y2="430"/>|
a$ = a$ + |<line x1="366" y1="422" x2="366" y2="533"/>|
a$ = a$ + |<line x1="490" y1="434" x2="490" y2="443"/>|
a$ = a$ + |<line x1="16"  y1="504" x2="162" y2="504"/>|
a$ = a$ + |<line x1="223" y1="430" x2="362" y2="429"/>|
a$ = a$ + |<line x1="235" y1="537" x2="294" y2="537"/>|
a$ = a$ + |<line x1="348" y1="537" x2="398" y2="537"/>|
a$ = a$ + |<line x1="231" y1="533" x2="229" y2="728"/>|
a$ = a$ + |<line x1="398" y1="533" x2="398" y2="572"/></g>|
' <!-- Current room -->
a$ = a$ + |<g style="fill:#ffffff; stroke:#ffffff; stroke-width:0;">|
a$ = a$ + |<polygon id="invitados" points="23,21 23,351 235,350 235,60 23,21"/>|
a$ = a$ + |<polygon id="dormitorio" points="23,512 23,722 221,722 221,529 358,529 358,438 167,438 167,512"/>|
a$ = a$ + |<polygon id="cocina" points="500,367 500,437 743,437 743,186 598,186 598,367"/>|
a$ = a$ + |<rect id="salon" x="253" y="62" width="326" height="288"/>|
a$ = a$ + |<rect id="servicio" x="23" y="368" width="126" height="126"/>|
a$ = a$ + |<rect id="bano" x="239" y="546" width="149" height="175"/></g>|
' <!-- temperature, humidity, pressure -->
a$ = a$ + |<g style="font-weight:bold; fill:aqua; stroke:blue; stroke-width:2; font-family:comic sans ms; font-size:1.75rem;">|
' cocina
a$ = a$ + |<text id="T0" x=640 y=290>22&#176;</text>|
a$ = a$ + |<text id="H0" x=640 y=330>40%</text>|
a$ = a$ + |<text id="L0" x=640 y=370>222 lx</text>|
' salon
a$ = a$ + |<text id="T1" x=390 y=170>22&#176;</text>|
a$ = a$ + |<text id="H1" x=390 y=210>40%</text>|
a$ = a$ + |<text id="L1" x=390 y=250>222 lx</text>|
' servicio
a$ = a$ + |<text id="T2" x=50 y=405>22&#176;</text>|
a$ = a$ + |<text id="H2" x=50 y=440>40%</text>|
a$ = a$ + |<text id="L2" x=50 y=475>222 lx</text>|
' invitados
a$ = a$ + |<text id="T3" x=98 y=170>22&#176;</text>|
a$ = a$ + |<text id="H3" x=98 y=210>40%</text>|
a$ = a$ + |<text id="L3" x=98 y=250>222 lx</text>|
' bano
a$ = a$ + |<text id="T4" x=280 y=605>22&#176;</text>|
a$ = a$ + |<text id="H4" x=280 y=640>40%</text>|
a$ = a$ + |<text id="L4" x=280 y=675>222 lx</text>|
' dormitorio
a$ = a$ + |<text id="T5" x=80 y=590>22&#176;</text>|
a$ = a$ + |<text id="H5" x=80 y=630>40%</text>|
a$ = a$ + |<text id="L5" x=80 y=670>222 lx</text>|

a$ = a$ + |</g></svg>|
html a$
return
For the tests of the correct reception of messages from the different rooms, I have used some small ESP-01 that simulate the definitive sensors by means of this program:

Code: [Local Link Removed for Guests]

' *********************
' **   EspNow Test   **
' **  V1.0 14/04/21  **
' *********************

' message structure: room,event,value 
' event type: (M)otion, (T)emperature, (H)umidity, (L)ight

DIM type$(3) = "M", "T", "H", "L"
aMAC$ = "CC:50:E3:92:5E:41" ' MAC address of the receiver

' start network espnow
ok = espnow.begin 
if ok = 0 then wlog "ESPNOW ON" else wlog "ESPNOW FAIL"
espnow.add_peer aMAC$ 
onEspNowError status

timer0 15000, sampling ' sample sensors every 15 seconds
wait

END

' ----------------------
sampling:
 
  room$ = str$(rnd(7))   ' random room between 0 and 6
  event$ = type$(rnd(4)) ' random event between 0 and 3
  
  select case event$
    case "M" : value$ = "1"                ' Motion detected
    case "T" : value$ = str$(rnd(31)+15)   ' Temperature between 15 and 45 degrees celsius
    case "H" : value$ = str$(rnd(80)+20)   ' Humidity between 20% and 100%
    case "L" : value$ = str$(rnd(601))     ' brightness between 0 and 600 
   end select
  
  message$ = room$ + "," + event$ + "," + value$        
  wlog message$
  espnow.write(message$, aMAC$)

return

' ----------------------
status:
  wlog "TX error on "; espnow.error$
return
image.png
You do not have the required permissions to view the files attached to this post.
User avatar
cicciocb
Site Admin
Posts: 1899
Joined: Mon Feb 03, 2020 1:15 pm
Location: Toulouse
Has thanked: 407 times
Been thanked: 1269 times
Contact:

Re: Sensor network over ethernet W5500

Post by cicciocb »

Super project, thanks a lot Fernando.
Post Reply