element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Pi Chef Design Challenge
  • Challenges & Projects
  • Design Challenges
  • Pi Chef Design Challenge
  • More
  • Cancel
Pi Chef Design Challenge
Blog Smart Range Hood - Intro to the control system - DHT22 (et al) [Buzzer, Light control] - Pi Chef Challenge - Blog post #7
  • Blog
  • Forum
  • Documents
  • Polls
  • Files
  • Events
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: aspork42
  • Date Created: 2 Mar 2018 6:17 AM Date Created
  • Views 972 views
  • Likes 7 likes
  • Comments 1 comment
  • node red
  • flows
  • dht22
  • home automation
  • pi chef design challenge
  • raspberry pi
  • ads1115
  • raspberrypi
  • nodered
  • dht11
  • automation
  • smart home
  • raspberry_pi_design_challenge
Related
Recommended

Smart Range Hood - Intro to the control system - DHT22 (et al) [Buzzer, Light control] - Pi Chef Challenge - Blog post #7

aspork42
aspork42
2 Mar 2018

My Goal - Make a sort of "hat" thing that sits above the stove to bring the stinky stinks to the outside world image

 

(i.e. a smart range hood which can run itself, text the home owners, summon the husband for dinner with images of dinner, and do other cool things too!)

 

See blog post #1 for links to all posts in the project.

 

Reading the Data

 

My last post got very long so I wanted to do one in more detail relating to the actual control of the system. So far, I have most the hardware running on a breadboard and controlled through Node Red.

In particular, I will focus on the DHT 22 temperature / humidity sensor. At this stage in the process, I have the DHT being read once per second. It pushes the current reading into an algorithm to decide IF the fan should run and HOW FAST the fan should run. It also allows manual control so that any user can push a button on the UI either locally or through the OpenHAB from their phone. Additionally, the temperature and humidity data is pushed into OpenHAB via MQTT once every 5 minutes.

 

I plan to do similar posts related to the other sensors as I get the controls finalized for them. As you'll see in the video, this one seems to be pretty rock solid for what it does in controlling the system, reporting status, and working with the different user interfaces.

 

As I noted in my previous post, this is the "flow" for the DHT sensor:

image

 

The "timestamp" node at the left is the main "tick" that runs my code. It fires once per second and since it is linked to the DHT sensor, this will trigger a reading of the sensor data. The DHT22 node comes from a package add-on to Node Red called "node-red-contrib-dht-sensor". This add-on handles all of the 1-wire communication protocol to the sensor and simplifies use to just defining the GPIO pin required. The sensor data is then passed to the following node labeled "ConvertToF". This is a "function" node allowing me to type basically any javascript compatible script. I'll expand the detail of the function node below.

 

At this stage, the flow splits into multiple paths. One path drops off the bottom of the image a feeds further nodes for automation. The graphic above also shows two paths that run through a rate limiter then post to an MQTT server. The rate limiter is a configurable "out of the box" timer node. In just a few simple clicks, I can set the timer node to allow only a single message every five minutes. This is perfect for this application since I want to read the sensor basically constantly so I can control the fan; but the home automation server doesn't need to be flooded with all that data; it just needs periodic updates. The final node is an MQTT publish node. It takes incoming data and publishes it to an MQTT broker as configured. Again, with Node Red this comes as an "out of the box" feature that the programmer can just drag out from the tool palette, configure a few options, link the node & deploy.

 

The raw sensor data is passed into the function node as a json message as follows:

{"topic":"DHT22","payload":"21.90","_msgid":"3572bca8.7bf4e4","humidity":"33.90","location":"DHT22","sensorid":"dht22"}

To use the temperature reading, I can simply read msg.payload in my javascript.  In this case, I need to convert from Celsius to American, so I use the 'ole conversion rule - F = (5/3) C + 32. I also round this to two decimal places with the .toFixed(2) function. To access the humidity in the json message, I use msg.humidity. These values are then sent out of the function node each on their own path. I also save out the temperature and humidity to global variables so they can be accessed from other nodes anywhere in the program. This is done through the global.set and global.get functions.

 

var tmpF = ((5/3) * msg.payload + 32).toFixed(2); // read temperature value, convert to F, and round to two digits.
global.set ("Temperature", tmpF); //save global variable for temperature


var humidity = msg.humidity; //read humidity value
global.set ("Humidity", humidity); // save global variable for humidity


return [{payload: tmpF}, {payload: humidity}]; //write data out to two different nodes so they can follow different paths

 

So the final set of steps to getting the DHT 22 running in Node Red on the raspberry Pi are as follows:

1. Install the DHT sensor library. (see blog post # 6)

2. Drag & drop all nodes as show above into a flow

3. Link all nodes in order

4. Update Function node as shown with code

5. Minor settings updates in the other nodes.

 

This entire process if done correctly should be quite fast. I did run into some issues initially getting the DHT library installed and since I don't use javascript on a daily basis there was a few syntax things that I ran into like rounding to two decimal places.

 

Doing cool things with the data

 

The difference between having lots of data and doing cool things with the data is the same difference as between being a hoarder and a smarty-pants.

 

Once I have the sensor data, I feed a main controller for the fan. I use a function block like I did above, but modify it to have four outputs. I trigger it from the end of the main "loop".

image

 

This Fan Controller node holds most the core logic for controlling the fan. It has two input nodes - one feeding from MQTT for manual override control and one triggering it from the end of the main loop. The node needs to look at all the sensor data (humidity, methane, LPG, CO, hydrogen) and decide if the fan needs to run. It also must accommodate any user just walking up and pressing the "run" button. To actually run the fan, I am triggering a set of relays. I need ONE and ONLY ONE relay to be on at a time. The logic block must decide firstly IF the fan should run, then HOW FAST to make it run, then trigger the appropriate relays. It additionally must also report out to MQTT to the rest of the home automation system what it is up to.

 

The logic ended up being pretty simple. I have a set of IF statements for each sensor. They compare the sensor reading against setpoints for each fan level. For the humidity sensor, I used 95%, 87%, and 80% as HIGH, MED, and LOW setpoints. The humidity must exceed 80% to turn ON. It will not turn OFF until the humidity is below 70%. This creates a hysteresis of at least 10%RH where we don't short-cycle the fan if the humidity hovers around a single ON/OFF setpoint value.

 

// Humidity sensor logic
     if(global.get("Humidity") > 95){ fanReqHumidity = 3;} // request high speed
else if(global.get("Humidity") > 87){ fanReqHumidity = 2;} // request high speed
else if(global.get("Humidity") > 80){ fanReqHumidity = 1;} // request low speed
else if(global.get("Humidity") < 70){ fanReqHumidity = 0;} //turn off need from humidity sensor

 

In this example, I am setting a "request" variable ("fanReqHumidity") for the humidity. It goes from 0 to 3 for off, low, med, high. Each other sensor has its own "request" variable. Farther down in the code, all I need to do is find the maximum request and accommodate that request. This means that any sensor exceeding the threshold can set a request and the fan will run the maximum requested speed. Humidity may not require the fan to run, but if CO gets too high, then it will come on. This uses the Math.max() function in line 3 below.

 

To accommodate manual fan control in this logic block, I can simply compare against the global variable "manualFanControl" to see which mode the system is running.

 

// Final control logic - find the highest required value
if(global.get("manualFanControl") === "FALSE"){
    global.set("FanSpeed", Math.max(fanReqHumidity, fanReqMethane, fanReqHydrogen, fanReqCO, fanReqLPG));
}
else{    
    global.set("FanSpeed", parseInt(global.get("manualFanSetting"))); 
}

 

Then to actually fire the correct outputs, there is a section which translates the speed of 0-3 (off/low/med/high) into the correct discrete outputs for the attached relays. I found out that the RaspberryPi seems to assert the pins HIGH by default instead of LOW which I am used to dealing with. Additionally, the relay board I purchased uses inverse logic - 0V means turn ON the relay and 3.3V means turn OFF the relay. So to get the a relay to clik ON, I have to write a 0 to the GPIO on the board. I use an IF/Else statement for the four different combinations of fan speed and write either a 1 or a 0 to each of the three fan relays. I additionally write out current fan speed to an MQTT node as the fourth output from the logic block.

 

if(global.get("FanSpeed") === 0) return  [{payload: 1},{payload: 1},{payload: 1},{payload: 0}]; // Fan off - all off
else if(global.get("FanSpeed") === 1) return [{payload: 0},{payload: 1},{payload: 1},{payload: 1}]; // low speed
else if(global.get("FanSpeed") === 2) return [{payload: 1},{payload: 0},{payload: 1},{payload: 2}]; // Med speed
else if(global.get("FanSpeed") === 3) return  [{payload: 1},{payload: 1},{payload: 0},{payload: 3}]; // High speed

 

Writing data out to specific outputs of NodeRed is done through an array. Each element of the array is written to the corresponding output from the node. I also needed to cast the values of 0 or 1 as a type called 'payload' to make this work correctly.

 

Finally, here is the complete (CURRENT) function block for the fan controller.

 

var fanReqHumidity; // number from 0-3 if humidity requests the fan
var fanReqMethane;  // fan request methane
var fanReqHydrogen; // fan request hydrogen
var fanReqCO;       // fan request CO
var fanReqLPG;      // fan request LPG

// Humidity sensor logic
     if(global.get("Humidity") > 95){ fanReqHumidity = 3;} // request high speed
else if(global.get("Humidity") > 87){ fanReqHumidity = 2;} // request med speed
else if(global.get("Humidity") > 80){ fanReqHumidity = 1;} // request low speed
else if(global.get("Humidity") < 70){ fanReqHumidity = 0;} //turn off from humidity sensor

// Methane sensor logic
     if(global.get("Methane") > 1000){ fanReqMethane = 3;}  // request high speed
else if(global.get("Methane") > 850){ fanReqMethane = 2;}   // request med speed
else if(global.get("Methane") > 750){ fanReqMethane = 1;}   // request low speed
else if(global.get("Methane") < 500){ fanReqMethane = 0;}   //turn off need from methane sensor

// Hydrogen sensor logic
     if(global.get("Hydrogen") > 2000){ fanReqHydrogen = 3;} // request high speed
else if(global.get("Hydrogen") > 1900){ fanReqHydrogen = 2;} // request med speed
else if(global.get("Hydrogen") > 1750){ fanReqHydrogen = 1;} // request low speed
else if(global.get("Hydrogen") < 1650){ fanReqHydrogen = 0;} //turn off need from hydrogen sensor

// CO sensor logic
     if(global.get("CO") > 12){ fanReqCO = 3;} // request high speed
else if(global.get("CO") > 9){ fanReqCO = 2;} // request med speed
else if(global.get("CO") > 8){ fanReqCO = 1;} // request low speed
else if(global.get("CO") < 7){ fanReqCO = 0;} // turn off need from CO sensor

// LPG sensor logic
     if(global.get("LPG") > 1000){ fanReqLPG = 3;} // request high speed
else if(global.get("LPG") > 850){ fanReqLPG = 2;}  // request med speed
else if(global.get("LPG") > 750){ fanReqLPG = 1;}  // request low speed
else if(global.get("LPG") < 500){ fanReqLPG = 0;}  // turn off need from LPG sensor


// Final control logic - find the highest required value
if(global.get("manualFanControl") === "FALSE"){
    global.set("FanSpeed", Math.max(fanReqHumidity, fanReqMethane, fanReqHydrogen, fanReqCO, fanReqLPG));
}
else{    
    global.set("FanSpeed", parseInt(global.get("manualFanSetting"))); 
}

if(global.get("FanSpeed") === 0) return  [{payload: 1},{payload: 1},{payload: 1},{payload: 0}]; // Fan off - all off
else if(global.get("FanSpeed") === 1) return [{payload: 0},{payload: 1},{payload: 1},{payload: 1}]; // low speed
else if(global.get("FanSpeed") === 2) return [{payload: 1},{payload: 0},{payload: 1},{payload: 2}]; // Med speed
else if(global.get("FanSpeed") === 3) return  [{payload: 1},{payload: 1},{payload: 0},{payload: 3}]; // High speed

 

 

Manual Control

Most users still expect to be able to just walk up to a device and turn it on. They generally don't want to be required to use their smartphone to do simple tasks like turn on the lights in the room or the coffee pot. The UI and the manual buttons will allow local control of the device. The current implementation of this uses OpenHAB as the mobile user interface and connects to the range hood over MQTT.

 

In general, manual control just involves setting a global variable called "manualFanControl" to TRUE and providing a requested speed. A timer node is used to give an appropriate timeout after which automatic mode will be enabled again.

 

Here is what the flow looks like:

image

 

So we are using an MQTT "listen" node under the topic called "home/kitchen/rangehood/fan/command" for any newly issued commands. There are also four UI button nodes with the little hand icon for the NodeRed user interface for manual control This is subject to change before the final design, but here is the current implementation accessible through a web browser:

image

So all of these nodes feed into a function node called "Enable Manual Control." This simply sets a global variable for manual control. The next node is a timer - once the timer expires then control reverts to automatic. For testing, I have left the timer at 2 seconds. In production I think I will use 30 minutes. Once automatic control takes back over, the fan speed will be set based on the sensor data as explained above.

 

One more little bit - I am using OpenHAB as my main home automation controller. The Range Hood will function autonomously of OpenHAB; but will still offer status info and take external data from the OpenHAB server. I am not going to give a lot of detail on how OpenHAB is set up, but I will post here the relevant .items file contents and .sitemap section that is shown in the video.

 

Sitemap file which controls the user interface -

Group item=Kitchen label="Range Hood" {

Switch item=RangeHoodFan mappings=[0="Off", 1="Low", 2="Med", 3="High"]

Switch item=RangeHoodLight icon=light
Text item=RangeHoodTemperature
Text item=RangeHoodHumidity
Text item=RangeHoodMethane
Text item=RangeHoodLPG
Text item=RangeHoodCO
Text item=RangeHoodHydrogen
Switch item=RangeHoodBuzzer 
Chart item=rangeHoodGasses period=h refresh=300000
Chart item=RangeHoodTemperature period=d refresh=300000
Chart item=RangeHoodHumidity period=d refresh=300000
}

 

.items file which defines the variables available to the system -

Group rangeHoodGasses


Number RangeHoodFan "Fan Speed"   { mqtt=">[mosquitto:home/kitchen/rangehood/fan/command:command:*:default], <[mosquitto:home/kitchen/rangehood/fan/status:state:default]"}
Switch RangeHoodLight "Light" { mqtt=">[mosquitto:home/kitchen/rangehood/light/state:command:*:default], <[mosquitto:home/kitchen/rangehood/light/status:state:default]"}
Switch RangeHoodBuzzer "Buzzer" { mqtt=">[mosquitto:home/kitchen/rangehood/buzzer/state:command:*:default], <[mosquitto:home/kitchen/rangehood/buzzer/status:state:default]"}


Number RangeHoodHumidity "Humidity [%.01f %%]"   {mqtt="<[mosquitto:home/kitchen/rangehood/humidity:state:default]"}
Number RangeHoodTemperature "Temperature [%.01f °F]"  {mqtt="<[mosquitto:home/kitchen/rangehood/temperature:state:default]"}


Number RangeHoodMethane "Methane [%s ppm]"   (rangeHoodGasses) {mqtt="<[mosquitto:home/kitchen/rangehood/methane:state:default]"}
Number RangeHoodLPG "LPG [%s ppm]"  (rangeHoodGasses) {mqtt="<[mosquitto:home/kitchen/rangehood/LPG:state:default]"}
Number RangeHoodCO "CO [%s ppm]"   (rangeHoodGasses) {mqtt="<[mosquitto:home/kitchen/rangehood/CO:state:default]"}
Number RangeHoodHydrogen "Hydrogen [%s ppm]"  (rangeHoodGasses) {mqtt="<[mosquitto:home/kitchen/rangehood/hydrogen:state:default]"}

 

Finally - here is a video demonstration showing the final controls inaction - err - I mean "in action." I also walk through the Node Red flows and you can catch glimpses of some of the other portions of the project. I also cover the power consumption of the complete system. If you only have a few minutes, check this one out. It is very neat since it show automatic control of the system based on sensor data.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

Node Red flow overview - this one is a little long, but covers all the stuff in this blog post + some extras. It explains in additional information the control system.

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

Before we end - here is a preview of where the sheet metal design ended up -

image

 

SSSSUUUUPPPPERRRR excited that this came in. Stay tuned for more info on all the details...

  • Sign in to reply

Top Comments

  • genebren
    genebren over 7 years ago +1
    Very nice update. It looks like things are working very well. Your range hood look awesome! Good job, keep up the good work. Gene
  • genebren
    genebren over 7 years ago

    Very nice update.  It looks like things are working very well.  Your range hood look awesome!

    Good job, keep up the good work.

    Gene

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube