💬 Insulated Whole House Fan


  • Admin

    @rechin304 No not yet. It's on the list but it will be winter here for a while so it's not at the top. When were you planning to build yours?



  • @petewill I already build the wooden box, and i have all electronic parts. I do wait for threaded rod, threaded Insert, Ball Bearing to arrive from china. I just finish today the shield that will hold arduino, testing lcd screen (i have a different version then you have, less pin's and no need for resistors). I will try to convert your schetch latter to V2 (still need to make an gateway for V2). If successful i will post the code.


  • Admin

    @rechin304 Ok, sounds good. Let me know if you get stuck and I'll do my best to help.



  • This is hat i made until now. I have two issues:

    1. DHT11 is not working (no temp or hum is shown)
    2. I use Domoticz as controller and i do not see the node connecting to it, even the clock is sync with gateway. Gateway is version 2. So please if you have some time to look at the code your help be highly appreciated. Thanks.
    /**
       The MySensors Arduino library handles the wireless radio link and protocol
       between your home built sensors/actuators and HA controller of choice.
       The sensors forms a self healing radio network with optional repeaters. Each
       repeater and gateway builds a routing tables in EEPROM which keeps track of the
       network topology allowing messages to be routed to nodes.
    
       Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
       Copyright (C) 2013-2015 Sensnology AB
       Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
    
       Documentation: http://www.mysensors.org
       Support Forum: http://forum.mysensors.org
    
       This program is free software; you can redistribute it and/or
       modify it under the terms of the GNU General Public License
       version 2 as published by the Free Software Foundation.
    
       Power monitoring code adapted from: http://henrysbench.capnfatz.com/henrys-bench/arduino-current-measurements/acs712-arduino-ac-current-tutorial/
     *******************************
    
       REVISION HISTORY
       Version 1.0 - Initial code
       Version 2.0 - Changed for Mysensors v2
       
       DESCRIPTION
       The code below will run a MySensors whole house fan with wall mounted lcd control panel.  The fan is installed in the attic and an insulated cover will 
       open/close to conserve energy.  The project cost a little over $300 US.  A comparable commercial product costs around $1200.
       
       FEATURES
       - Physical button switch to control on/off in case there are ever issues with radio communications.  
       - DHT22 sensor for temp/humidity monitoring in the attic
       - LCD screen displays status, temp/humidity, errors & date/time
       - If an error occurs a message is sent to the gateway
       - When the unit looses power it will make sure the cover is closed and the fan is off after power is restored.
       - Safety Features
    	- The cover will wait to close until power has been shut off to the fan
    	- Customizable over current protection on the cover motor (automatically shut off if the cover gets stuck)
    	- Customizable cover close time limit (if it slips out off the coupling the motor won't run indefinitely)
    
       NOTE
       This program is too large to run with all debugging and the display enabled.
       To upload either comment out "#define DEBUG_ON" in the code below or comment out
       "#define DEBUG" in MyConfig.h in the MySensors library.
       For troubleshooting "#ifdef TFT_DISPLAY_ON" can be commented out so all debugging
       messages can be output to the serial monitor
    
    */
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    #define MY_RF24_PA_LEVEL RF24_PA_MAX
    
    #include <MySensors.h>
    #include <SPI.h>
    #include <Bounce2.h>
    #include <DHT.h>
    #include <Adafruit_GFX.h>    // Core graphics library
    #include <Adafruit_ST7735.h> // Hardware-specific library
    #include <Time.h>
    #include <TimeLib.h>
    
    //#define NODE_ID AUTO //or set to AUTO to have the gateway assign an ID
    
    //#define NODE_REPEAT false //change to true to set to a repeating/relaying node
    
    
    #define MY_NODE_ID AUTO  //set to AUTO to have the gateway assign an ID
    #define SKETCH_NAME "House Fan Mysensors v2"
    #define SKETCH_VERSION "2.1"
    
    #define FAN_ID 0   	// ID of the fan sensor child
    #define ERROR_ID 1 	// ID of the alert child 
    #define	HUM_ID 2 	//ID of the humidity child
    #define TEMP_ID 3 	//ID of the temp child
    
    #define BUTTON_PIN 2  				//Pin for the on/off button 
    // Set this to the pin you connected the DHT's data pin to
    #define DHT_DATA_PIN A0
    // Set this offset if the sensor has a permanent small offset to the real temperatures
    #define SENSOR_TEMP_OFFSET 0
    static const uint64_t UPDATE_INTERVAL = 60000;
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
    // the value didn't change since;
    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    #define FAN_RELAY_PIN  A1  			//Pin number for relay that will control the fan
    #define COVER_CLOSE_LIMIT_PIN A2 	//Pin number for the "cover closed" limit switch
    #define COVER_OPEN_LIMIT_PIN A3 	//Pin number for the "cover open" limit switch
    #define COVER_CLOSE_PIN A4 			//Pin number for the "cover close" L298N motor control board
    #define COVER_OPEN_PIN A5			//Pin number for the "cover open" L298N motor control board
    #define FAN_POWER_PIN A6			//Pin number for the ACS712 monitoring the fan
    #define COVER_POWER_PIN A7			//Pin number for the ACS712 monitoring the cover motor
    
    #define TFT_DISPLAY_ON //Use to turn on/off display functionality (need to turn off for debugging because code is too large).
    
    #ifdef TFT_DISPLAY_ON
    // TFT display and SD card pins.  They will share the software SPI interface.
    #define SPI_SCK 8  //Also can be labeled CLK on display
    #define SPI_DI  4 //Labeled MISO on display
    #define SPI_DO  7  //Labeled MOSI on display
    //#define SD_CS   5  // Chip select line for SD card (not currently used)
    #define TFT_CS  3
    #define TFT_DC  6 //Labeled RS
    #define TFT_RST 0  // you can also connect this to the Arduino reset
    Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, SPI_DO, SPI_SCK, TFT_RST);
    #endif
    
    #define DEBUG_ON   // comment out to supress serial monitor output
    
    #ifdef DEBUG_ON
    #define DEBUG_PRINT(x)   Serial.print(x)
    #define DEBUG_PRINTLN(x) Serial.println(x)
    #define SERIAL_START(x)  Serial.begin(x)
    #else
    #define DEBUG_PRINT(x)
    #define DEBUG_PRINTLN(x)
    #define SERIAL_START(x)
    #endif
    
    #define RELAY_ON 1 //Switch to 0 if fan relay is off when it should be on
    #define RELAY_OFF 0 //Switch to 1 if fan relay is on when it should be off
    #define DWELL_TIME 50 //Time to wait between radio messages sent (helps prevent missed messages)
    #define closingStall 465 //The value of the ACS712 when the cover motor is stopped while closing. This value should be less than the normal operating power draw.
    #define openingStall 580 //The value of the ACS712 when the cover motor is stopped while opening.  This value should be greater than the normal operating power draw.
    #define coverLimitTime 37000 //Slightly over the time it takes for the cover to fully open/close in milliseconds.  This will prevent the cover motor from running indefinitely.
    
    //Fan power reading variables. You may need to adjust these depending on your ACS712 model and house voltage
    uint8_t mVperAmp = 69; //had to adjust for my sensor you may need to adjust yours a well // use 185 for 5A Module, 100 for 20A Module and 66 for 30A Module
    uint8_t houseVoltage = 220; //Voltage of your house wiring (110 or 220) 
    
    Bounce debouncerOnOff = Bounce();
    Bounce debouncerClosedState = Bounce();
    Bounce debouncerOpenState = Bounce();
    uint8_t fanButtonPrev = 0;
    uint8_t fanState = 0;
    uint8_t fanStatePrevious = 1;
    uint8_t fanRelayState;
    uint8_t coverMoving = 0;
    uint8_t	coverClosedState = LOW;
    uint8_t	coverOpenState = LOW;
    uint8_t errorState = 0; //Used to keep track of errors.  Can be reset by manually pushing button
    uint8_t fanPowerReading = 0;
    int coverPowerReading = 0;
    unsigned long currentMillis; //used for timers
    unsigned long powerReadMillis; //Used read power every second
    unsigned long powerUpdateMillis; //Used to update power usage on LCD and gateway
    unsigned long coverMillis;
    unsigned long dhtMillisPrev;
    unsigned long dhtDelay = 305000;	//5 minutes 5 seconds.  Offset is in case of power failure I don't want all my nodes reporting at the same time.
    unsigned long lastGetTime; //Used for getting time from gateway
    
    uint8_t lastSecond;
    uint8_t lastMinute;
    uint8_t lastHour;
    
    DHT dht;
    float lastTemp = 0;
    float lastHum = 0;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    boolean metric = true; //Set to true if you use the metric system
    
    //Fan power reading variables.
    double Voltage = 0; //Voltage read from analog pin (used to calc power)
    double VRMS = 0;
    double AmpsRMS = 0;
    uint16_t wattTotal = 0; //Used to calculate the watts used for the last minute
    int wattAvg = 0;
    int wattAvgPrev = 0;
    uint8_t wattCount = 0; //Will be used to divide watts
    uint16_t pMaxValue = 0; // store max value here
    uint16_t pMinValue = 1024; // store min value here
    
    
    //MySensor gw;
    MyMessage msgFan(FAN_ID, V_STATUS);
    MyMessage msgFanPwr(FAN_ID, V_WATT);
    MyMessage msgError(ERROR_ID, V_TRIPPED);
    MyMessage msgHum(HUM_ID, V_HUM);
    MyMessage msgTemp(TEMP_ID, V_TEMP);
    
    void presentation()  
    { 
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
      present(FAN_ID, S_BINARY);
      wait(DWELL_TIME);
      present(ERROR_ID, S_MOTION);
      wait(DWELL_TIME);
      present(HUM_ID, S_HUM);
      wait(DWELL_TIME);
      present(TEMP_ID, S_TEMP);
      wait(DWELL_TIME);
      metric = getConfig().isMetric;
    }
    
    void setup()
    {
      delay(2000); //Allow time for sensors to power up
      
    requestTime();
      // Send the sketch version information to the gateway and Controller
    
    
      dht.setup(DHT_DATA_PIN);
        if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
        Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
      }
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      sleep(dht.getMinimumSamplingPeriod());
    
      // Make sure relays are off when starting up
      digitalWrite(FAN_RELAY_PIN, RELAY_OFF);
      digitalWrite(COVER_OPEN_PIN, LOW);
      digitalWrite(COVER_CLOSE_PIN, LOW);
    
      // Set the pin mode
      pinMode(FAN_RELAY_PIN, OUTPUT);
      pinMode(COVER_OPEN_PIN, OUTPUT);
      pinMode(COVER_CLOSE_PIN, OUTPUT);
      pinMode(COVER_OPEN_LIMIT_PIN, INPUT_PULLUP);
      pinMode(COVER_CLOSE_LIMIT_PIN, INPUT_PULLUP);
      pinMode(BUTTON_PIN, INPUT_PULLUP); // Setup the on/off button and activate internal pull-up
    
      // After setting up the pin modes, setup debouncers
      debouncerOnOff.attach(BUTTON_PIN);
      debouncerOnOff.interval(50);
      debouncerOpenState.attach(COVER_OPEN_LIMIT_PIN);
      debouncerOpenState.interval(50);
      debouncerClosedState.attach(COVER_CLOSE_LIMIT_PIN);
      debouncerClosedState.interval(50);
    
      // Register all sensors to gw (they will be created as child devices)
    
    
      send(msgError.set(0)); // Reset Alert state
    
      //Check the cover slide limit switch values
      debouncerOpenState.update();
      coverOpenState = debouncerOpenState.read();
    
      debouncerClosedState.update();
      coverClosedState = debouncerClosedState.read();
    
      metric = getConfig().isMetric;
    
    unsigned long functionTimeout = millis();
      while (timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL)
      {
        requestTime(); 
        DEBUG_PRINTLN(F("Getting Time"));
        wait(1000); // call once per second
        DEBUG_PRINTLN(F("."));
      }
    
    #ifdef TFT_DISPLAY_ON
      //**Note: I had a red tab LCD but the black tab setting worked the best for me
      // If your TFT's plastic wrap has a Black Tab, use the following:
      tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
      // If your TFT's plastic wrap has a Red Tab, use the following:
      //tft.initR(INITR_REDTAB);   // initialize a ST7735R chip, red tab
      // If your TFT's plastic wrap has a Green Tab, use the following:
      //tft.initR(INITR_GREENTAB); // initialize a ST7735R chip, green tab
    
      //Initial Setup - Set state to Idle
      tft.drawLine(0, 7, 160, 7, tft.Color565(123, 123, 123)); //Setup
      tft.fillRect(0, 8, 160, 21, tft.Color565(80, 80, 80)); //Setup
      tft.drawLine(0, 29, 160, 29, tft.Color565(34, 34, 34)); //Setup
      tft.drawLine(0, 110, 160, 110, ST7735_WHITE); //Setup
      tft.fillRect(0, 111, 160, 43, tft.Color565(230, 230, 230)); //Setup
      tft.drawLine(0, 153, 160, 153, tft.Color565(170, 170, 170)); //Setup
    
      updateTime();
      updateTemp();
      updateHum();
    
    #endif
    
      currentMillis = millis();
      coverMillis = currentMillis;
    
      //Make sure the fan is off and the cover is closed when first powered on
      fanOff();
    }
    
    
    void loop()
    {
      // Force reading sensor, so it works also after sleep()
      dht.readSensor(true);
      
      currentMillis = millis(); //Set the current millis (used for timers)
    
      //Check the cover slide limit switch values
      debouncerOpenState.update();
      coverOpenState = debouncerOpenState.read();
    
      debouncerClosedState.update();
      coverClosedState = debouncerClosedState.read();
      //  DEBUG_PRINT(F("coverClosedState = "));
      //  DEBUG_PRINTLN(coverClosedState);
    
      //There is a spike in current when the motor is first turned on.  We need to stop reading for a short period so the motor doesn't immedately turn off
      if (currentMillis - coverMillis > 1500)
      {
        coverPowerReading = analogRead(COVER_POWER_PIN); //change back when sensor is attached
        //DEBUG_PRINT(F("coverPowerReading = "));
        //DEBUG_PRINTLN(coverPowerReading);
        if (coverPowerReading > closingStall && coverPowerReading < openingStall)
        {
          //Cover motor power draw is within limits
          coverPowerReading = 0;
        }
        else
        {
          //Cover motor power draw is over the limit.  Motor has stalled.
          coverPowerReading = 1;
        }
      }
    
      debouncerOnOff.update();
      uint8_t fanButton = debouncerOnOff.read(); // Get the update value
      //DEBUG_PRINTLN(fanButton);
      if (fanButton != fanButtonPrev && fanButton == 0) {
        if (coverMoving == 1)
        {
          //If the cover is already moving, change directions.
          fanStatePrevious = fanState;
          coverMoving = 0;
        }
        fanState = fanState ? 0 : 1;
        DEBUG_PRINT(F("fanState value changed to: "));
        DEBUG_PRINTLN(fanState);
        send(msgFan.set(fanState), true); // Send new state and request ack back
        errorState = 0;
        wait(DWELL_TIME);
        send(msgError.set(0)); // Reset Alert state
        coverMillis = currentMillis; //Set the millis (used to keep track of cover close/open times)
      }
      fanButtonPrev = fanButton;
    
      if (fanState != fanStatePrevious && fanState == 0 && errorState == 0)
      {
        fanOff();
      }
      if (fanState != fanStatePrevious && fanState == 1 && errorState == 0)
      {
        fanOn();
      }
    
      if (currentMillis - dhtMillisPrev > dhtDelay)
      {
        float temperature = dht.getTemperature();
    
        if (isnan(temperature))
        {
          DEBUG_PRINTLN(F("Failed reading temperature from DHT"));
        }
        else
        {
          if (!metric)
          {
            temperature = dht.toFahrenheit(temperature);
          }
          if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS)
          {
            lastTemp = temperature;
            send(msgTemp.set(temperature, 1));
            wait(DWELL_TIME);
    #ifdef TFT_DISPLAY_ON
            updateTemp();
    #endif
            DEBUG_PRINT(F("Temperature is: "));
            DEBUG_PRINTLN(temperature);
          }
        }
        float humidity = dht.getHumidity();;
        if (isnan(humidity))
        {
          DEBUG_PRINTLN(F("Failed reading humidity from DHT"));
        } else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS)
        {
          lastHum = humidity;
          nNoUpdatesHum = 0;
          send(msgHum.set(humidity, 1));
          wait(DWELL_TIME);
    #ifdef TFT_DISPLAY_ON
          updateHum();
    #endif
    
          DEBUG_PRINT(F("Humidity is: "));
          DEBUG_PRINTLN(humidity);
        } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
        dhtMillisPrev = currentMillis;
      }
    
      /*
        Check power usage here
        I want to check it every second then send it every minute (when changed) to the gateway and LCD
        In the "every second" check it should get a running average so it would divide by the number of seconds
      */
    
      if (currentMillis - powerReadMillis < 1000)
      {
        //Read power every second
        uint16_t readValue = analogRead(FAN_POWER_PIN);
        //DEBUG_PRINT(F("readValue: "));
        //DEBUG_PRINTLN(readValue);
    
        // see if you have a new pMaxValue
        if (readValue > pMaxValue)
        {
          /*record the maximum sensor value*/
          pMaxValue = readValue;
        }
        if (readValue < pMinValue)
        {
          /*record the maximum sensor value*/
          pMinValue = readValue;
        }
      }
      else
      {
        //Calulate power usage and update gateway if necessary
        // Subtract min from max
        Voltage = ((pMaxValue - pMinValue) * 5.0) / 1024.0;
        VRMS = (Voltage / 2.0) * 0.707;
        AmpsRMS = (VRMS * 1000) / mVperAmp;
    
        if (AmpsRMS < .15) //filter out low readings when fan is off
        {
          AmpsRMS = 0;
        }
        DEBUG_PRINT(F("Amps RMS: "));
        DEBUG_PRINT(AmpsRMS);
    
        wattTotal += houseVoltage * AmpsRMS;
        DEBUG_PRINT(F(".  Watt Total: "));
        DEBUG_PRINT(wattTotal);
        wattCount ++;
        DEBUG_PRINT(F(".  Watt Count: "));
        DEBUG_PRINTLN(wattCount);
        powerReadMillis = currentMillis;
        //Reset max and min values
        pMaxValue = 0;
        pMinValue = 1024;
    
        //Update fanPowerReading to make sure the fan is off before closing the cover
        fanPowerReading = AmpsRMS > 1 ? 1 : 0;
        DEBUG_PRINT(F("fanPowerReading: "));
        DEBUG_PRINTLN(fanPowerReading);
    
        //Update Gateway and LCD every minute if necessary
        if (currentMillis - powerUpdateMillis > 60000)
        {
          //We don't want to flood the gateway with updates so if the last reading was close to the current one we don't need to send the new reading
          wattAvg = wattTotal / wattCount;
          DEBUG_PRINT(F("Watt Average: "));
          DEBUG_PRINTLN(wattAvg);
    
          //Only update if last usage was different by 2 watts
          if (wattAvgPrev - wattAvg > 2 || wattAvg - wattAvgPrev > 2)
          {
            //Send to gateway
            send(msgFanPwr.set(wattAvg));
    
    #ifdef TFT_DISPLAY_ON
            if (fanPowerReading == 1)
            {
              //Update LCD if running
              tft.setTextColor(ST7735_WHITE, tft.Color565(53, 47, 125));
              tft.setFont();
              tft.setTextSize(1);
              tft.setCursor(5, 95);
              tft.print("Watts: "); //First line of text 20 characters max
              tft.print(wattAvg);
              tft.print("  ");
              DEBUG_PRINT(F("Watts update display: "));
              DEBUG_PRINTLN(wattAvg);
            }
    
    
    #endif
    
          }
          wattAvgPrev = wattAvg;
    
          //Reset watt trackers
          wattTotal = 0;
          wattCount = 0;
    
          powerUpdateMillis = currentMillis;
    
          //Using this if statement to update the time every minute
    #ifdef TFT_DISPLAY_ON
          //Update Time on Display every minute
          updateTime();
    #endif
        }
      }
    
      if (currentMillis - lastGetTime >= 3600000UL) // updates clock time and gets zone times from gateway once every hour
      {
        DEBUG_PRINTLN(F("Requesting time and valve data from Gateway..."));
    
        lastGetTime = millis();
      }
    }
    
    void fanOff() {
      /*
         1. Turn off the fan
         2. Make sure it's off before we start closing the cover
         3. Close cover
            a. Start a timer for how long the closing should take
            b. Stop the motor when the limit switch is hit
         4. Ensure the limit switch has been pressed and the timer didn't run out.  If it did send an error message (via motion sensor).
         5. Send "off" message to gateway/controller
      */
    
      //DEBUG_PRINTLN(F("In the fanOff function"));
      if (fanRelayState == RELAY_ON)
      {
        DEBUG_PRINTLN(F("Turning off fan"));
        //Turn off fan and set fan relay state to 0
        digitalWrite(FAN_RELAY_PIN, RELAY_OFF);
        fanRelayState = RELAY_OFF;
    
      }
      if (currentMillis - coverMillis < coverLimitTime)
      {
        if (coverPowerReading == 0)
        {
          //Make sure the fan is off before closing the cover to prevent damage to the cover and fan
          if (fanPowerReading == 0)
          {
            //Start closing the cover
            //Set the close pin on the L298N board to high
    
            if (coverMoving == 0)
            {
              DEBUG_PRINTLN(F("Closing Cover"));
              digitalWrite(COVER_CLOSE_PIN, HIGH);
              //Set COVER_OPEN_PIN to low just to be safe
              digitalWrite(COVER_OPEN_PIN, LOW);
    
              //Update the LCD with "Closing" status message
    #ifdef TFT_DISPLAY_ON
              tft.setTextColor(ST7735_WHITE, tft.Color565(53, 47, 125));
              tft.setFont();
              tft.setTextSize(1);
              tft.setCursor(5, 95);
              tft.print("CLOSING COVER     "); //First line of text 20 characters max
    #endif
              coverMoving = 1;
            }
    
            if (coverClosedState == LOW)
            {
              //The cover is closed.  Stop motor and send status to gateway.
              digitalWrite(COVER_CLOSE_PIN, LOW);
              fanStatePrevious = fanState;
              send(msgFan.set(fanState), true); // Send new state with Ack
              coverMoving = 0;
    
    #ifdef TFT_DISPLAY_ON
              //Update LCD
              wait(200); //Wait for radio SPI to stop (otherwise display is garbled)
              updateTFTStatus(0); //Set status to idle state
    #endif
            }
          }
        }
        else
        {
          //Cover motor is using too much power.  Stop everything to avoid damage.
          DEBUG_PRINTLN(F("The slide motor is using too much power!"));
          digitalWrite(COVER_CLOSE_PIN, LOW);
          digitalWrite(COVER_OPEN_PIN, LOW);
          errorState = 1; //Set the error state so it doesn't keep trying to close
          send(msgError.set(1)); // Send alert state to gateway
    #ifdef TFT_DISPLAY_ON
          //Update LCD
          updateTFTStatus(2); //Set status to error state
          errorOvercurrent(); //More detailed error message
    #endif
        }
      }
      else
      {
        /*Things have taken too long there must be an error.  Print it out to the LCD and send trigger to gateway
          Possible errors could be:
          Fan did not shut off.
          Cover did not fully close in time (slide jam, motor slip etc.)
          Over current in cover motor (jammed?)
        */
        //Send commands to stop everything to avoid damage.
        DEBUG_PRINTLN(F("Cover time exceeded"));
        digitalWrite(FAN_RELAY_PIN, RELAY_OFF);
        digitalWrite(COVER_CLOSE_PIN, LOW);
        digitalWrite(COVER_OPEN_PIN, LOW);
        errorState = 1; //Set the error state so it doesn't keep trying to close
        send(msgError.set(1)); // Send alert state to gateway
    
    #ifdef TFT_DISPLAY_ON
        //Update LCD
        updateTFTStatus(2); //Set status to error state
        errorTime(); //Write more detailed error to LCD
    #endif
      }
    }
    
    void fanOn() {
    
      /*
        1. Open the cover
          a. Start a timer to keep track of how long the cover has been opening 
          b. Stop the motor when the limit switch is hit
        2. Ensure the limit switch has been pressed and the timer didn't run out.  If it did send an error message.
        3. Start the fan
        4. Send "on" message to gateway/controller
      */
    
      if (currentMillis - coverMillis < coverLimitTime)
      {
        if (coverPowerReading == 0)
        {
          //Start opening the cover
          if (coverMoving == 0)
          {
            DEBUG_PRINTLN(F("Opening Cover"));
    
            //Set COVER_CLOSE_PIN to low just to be safe
            digitalWrite(COVER_CLOSE_PIN, LOW);
            digitalWrite(COVER_OPEN_PIN, HIGH);
            coverMoving = 1;
    
    #ifdef TFT_DISPLAY_ON
            wait(200); //Wait for radio communication to stop (otherwise display is garbled because of SPI conflicts)
            //Update LCD
            updateTFTStatus(1); //Set status to idle state
    #endif
    
          }
    
          if (coverOpenState == LOW)
          {
            //The cover is open.  Stop motor and send status to gateway.
            digitalWrite(COVER_OPEN_PIN, LOW);
            fanStatePrevious = fanState;
            //Turn on Fan
            digitalWrite(FAN_RELAY_PIN, RELAY_ON);
            fanRelayState = RELAY_ON;
            coverMoving = 0;
          }
        }
        else
        {
          //Cover motor is using too much power.  Stop everything to avoid damage.
          DEBUG_PRINTLN(F("The cover motor is using too much power!"));
          digitalWrite(COVER_CLOSE_PIN, LOW);
          digitalWrite(COVER_OPEN_PIN, LOW);
          errorState = 1; //Set the error state so it doesn't keep trying to close
          send(msgError.set(1)); // Send alert state to gateway
    #ifdef TFT_DISPLAY_ON
          //Update LCD
          updateTFTStatus(2); //Set status to error state
          errorOvercurrent(); //More detailed error message
    #endif
        }
      }
      else
      {
        /*Things have taken too long there must be an error.  Print it out to the LCD and send trigger to gateway
          Possible errors could be:
          Cover did not fully open in time (slide jam, motor slip etc.)
          Overcurrent in cover motor (jammed?)
        */
        //Send commands to stop everything to avoid damage.
        DEBUG_PRINTLN(F("Cover time exceeded"));
        digitalWrite(COVER_CLOSE_PIN, LOW);
        digitalWrite(COVER_OPEN_PIN, LOW);
        errorState = 1; //Set the error state so it doesn't keep trying to close
    
    #ifdef TFT_DISPLAY_ON
        //Update LCD
        updateTFTStatus(2); //Set status to error state
        tft.setCursor(5, 90);
        //More detailed error message
        errorTime();
    #endif
      }
    
    }
    
    
    void receive(const MyMessage & message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.isAck()) {
        DEBUG_PRINTLN(F("This is an ack from gateway"));
      }
    
      if (message.type == V_LIGHT && !message.isAck()) {
        // Change relay state
        fanState = message.getBool();
        if (coverMoving == 1)
        {
          //If the cover is already moving, check to see if we need to change directions
          DEBUG_PRINT(F("Cover is moving"));
          if (fanState == fanStatePrevious)
          {
            //We need to change directions
            fanStatePrevious = fanState ? 0 : 1;
            coverMoving = 0;
          }
        }
        coverMillis = millis(); //Set the millis (used to keep track of cover close/open times)
    
        // Write some debug info
        DEBUG_PRINT(F("Incoming change for sensor:"));
        DEBUG_PRINT(message.sensor);
        DEBUG_PRINT(F(", New status: "));
        DEBUG_PRINTLN(fanState);
      }
    }
    
    // This is called when a new time value was received
    void receiveTime(unsigned long time) {
      // Ok, set incoming time 
      setTime(time);
    }
    
    #ifdef TFT_DISPLAY_ON
    void updateTFTStatus(uint8_t bgStat)
    {
      //bgStat: 0 = "Idle", 1 = "Running", 2 = "Error"
      //Idle Color = 37, 125, 20
      //Running Color = 53, 47, 125
      //Error Color = 155, 26, 26
    
      uint8_t r, g, b;
      const char *displayStatus[] = {
        "Idle", "Running", "Error"
      };
      if (bgStat == 0)
      {
        //Idle
        r = 37;
        g = 125;
        b = 20;
      }
      else if (bgStat == 1)
      {
        //Running
        r = 53;
        g = 47;
        b = 125;
      }
      else
      {
        //Error
        r = 155;
        g = 26;
        b = 26;
      }
    
      tft.fillRect(0, 0, 160, 7, tft.Color565(r, g, b));
      tft.fillRect(0, 30, 160, 80, tft.Color565(r, g, b));
      tft.fillRect(0, 154, 160, 6, tft.Color565(r, g, b));
    
      tft.setCursor(5, 40);
      tft.setTextColor(ST7735_WHITE);
      tft.setTextSize(1);
      tft.println("Status");
    
      tft.setCursor(5, 65);
      tft.setTextColor(ST7735_WHITE);
      tft.setFont();
      //tft.setTextSize(3);
      tft.setTextSize(bgStat == 1 ? 2 : 3); //The word "Running" doesn't fit with text size 3.
      tft.println(displayStatus[bgStat]);
    
    }
    void errorOvercurrent()
    {
      tft.setCursor(5, 90);
      tft.setTextColor(ST7735_WHITE);
      tft.setFont();
      tft.setTextSize(1);
      tft.println("Motor overcurrent"); //First line of text 20 characters max
      tft.setCursor(5, 101);
      tft.println("Check cover slide"); //Second line of text 20 characters max
    }
    void errorTime()
    {
      tft.setCursor(5, 90);
      tft.setTextColor(ST7735_WHITE);
      tft.setFont();
      tft.setTextSize(1);
      tft.println("Time exceeded"); //First line of text 20 characters max
      tft.setCursor(5, 100);
      tft.println("Check cover slide"); //Second line of text 20 characters max
    }
    void updateTime()
    {
      //Update Time
      tft.setCursor(5, 17);
      tft.setTextColor(ST7735_WHITE, tft.Color565(80, 80, 80));
      tft.setTextSize(1);
      tft.print(hourFormat12());
      tft.print(minute() < 10 ? F(":0") : F(":"));
      tft.print(minute());
      tft.print(isAM() ? F("am") : F("pm"));
      tft.print(month() < 10 ? F(" 0") : F(" "));
      tft.print(month());
      tft.print(day() < 10 ? F("/0") : F("/"));
      tft.print(day());
      tft.print(F("/"));
      tft.print(year() % 100);
      tft.print(F(" "));
    }
    void updateTemp()
    {
      //Update Temperature
      tft.setCursor(5, 120);
      tft.setTextColor(tft.Color565(80, 80, 80), tft.Color565(230, 230, 230));
      tft.setTextSize(1);
      tft.print("Temp: ");
      tft.print(lastTemp, 1);
      tft.print((char)247);
      tft.print(" ");
    }
    void updateHum()
    {
      //Update Humidity
      tft.setCursor(5, 140);
      tft.setTextColor(tft.Color565(80, 80, 80), tft.Color565(230, 230, 230));
      tft.setTextSize(1);
      tft.print("Humidity: ");
      tft.print(lastHum, 1);
      tft.print("% ");
    }
    #endif
    


  • Small progress. It can be seen now in Domoticz, however DHT11 not working.



  • Excellent project. However, have you considered any possibility of condensation of humid air in the attic? At least where I live, that would become a problem.



  • In my case the air will go outside attic (i have a shaft for ventilation).


  • Admin

    @Nuubi You need to have proper venting in your attic to use a fan like this. If you have the venting the humidity should not be a problem because it will pull fresh air from the outside through your house and out the attic vents. I don't live in a high humidity area so maybe the venting in attics is different there though.


  • Admin

    @rechin304 said:

    Small progress. It can be seen now in Domoticz, however DHT11 not working.

    Are you sure you have the wiring correct? Does it show in the serial monitor but not Domoticz or neither place?



  • Hi @petewill , i do not see anything on serial monitor related to temp or hum, and yes is connected correctly on A0, everything now works ok, except temp and hum. I do not have yet an DHT22 to test.


  • Admin

    @rechin304 Strange. Did you enable debugging in the code (uncomment this line "//#define DEBUG_ON")? Without that line enabled you won't see anything in the serial monitor.



  • Yes, debug is enabled, see the code adapted for v2, below. I have build separate node for testing only temp and hum and no data is coming too (several DHT11 used).. i used example that come from library. (example used is this https://github.com/mysensors/MySensorsArduinoExamples/blob/master/examples/DhtTemperatureAndHumiditySensor/DhtTemperatureAndHumiditySensor.ino )

    @rechin304 said:

    This is hat i made until now. I have two issues:

    1. DHT11 is not working (no temp or hum is shown)
    2. I use Domoticz as controller and i do not see the node connecting to it, even the clock is sync with gateway. Gateway is version 2. So please if you have some time to look at the code your help be highly appreciated. Thanks.
    /**
       The MySensors Arduino library handles the wireless radio link and protocol
       between your home built sensors/actuators and HA controller of choice.
       The sensors forms a self healing radio network with optional repeaters. Each
       repeater and gateway builds a routing tables in EEPROM which keeps track of the
       network topology allowing messages to be routed to nodes.
    
       Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
       Copyright (C) 2013-2015 Sensnology AB
       Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
    
       Documentation: http://www.mysensors.org
       Support Forum: http://forum.mysensors.org
    
       This program is free software; you can redistribute it and/or
       modify it under the terms of the GNU General Public License
       version 2 as published by the Free Software Foundation.
    
       Power monitoring code adapted from: http://henrysbench.capnfatz.com/henrys-bench/arduino-current-measurements/acs712-arduino-ac-current-tutorial/
     *******************************
    
       REVISION HISTORY
       Version 1.0 - Initial code
       Version 2.0 - Changed for Mysensors v2
       
       DESCRIPTION
       The code below will run a MySensors whole house fan with wall mounted lcd control panel.  The fan is installed in the attic and an insulated cover will 
       open/close to conserve energy.  The project cost a little over $300 US.  A comparable commercial product costs around $1200.
       
       FEATURES
       - Physical button switch to control on/off in case there are ever issues with radio communications.  
       - DHT22 sensor for temp/humidity monitoring in the attic
       - LCD screen displays status, temp/humidity, errors & date/time
       - If an error occurs a message is sent to the gateway
       - When the unit looses power it will make sure the cover is closed and the fan is off after power is restored.
       - Safety Features
    	- The cover will wait to close until power has been shut off to the fan
    	- Customizable over current protection on the cover motor (automatically shut off if the cover gets stuck)
    	- Customizable cover close time limit (if it slips out off the coupling the motor won't run indefinitely)
    
       NOTE
       This program is too large to run with all debugging and the display enabled.
       To upload either comment out "#define DEBUG_ON" in the code below or comment out
       "#define DEBUG" in MyConfig.h in the MySensors library.
       For troubleshooting "#ifdef TFT_DISPLAY_ON" can be commented out so all debugging
       messages can be output to the serial monitor
    
    */
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    #define MY_RF24_PA_LEVEL RF24_PA_MAX
    
    #include <MySensors.h>
    #include <SPI.h>
    #include <Bounce2.h>
    #include <DHT.h>
    #include <Adafruit_GFX.h>    // Core graphics library
    #include <Adafruit_ST7735.h> // Hardware-specific library
    #include <Time.h>
    #include <TimeLib.h>
    
    //#define NODE_ID AUTO //or set to AUTO to have the gateway assign an ID
    
    //#define NODE_REPEAT false //change to true to set to a repeating/relaying node
    
    
    #define MY_NODE_ID AUTO  //set to AUTO to have the gateway assign an ID
    #define SKETCH_NAME "House Fan Mysensors v2"
    #define SKETCH_VERSION "2.1"
    
    #define FAN_ID 0   	// ID of the fan sensor child
    #define ERROR_ID 1 	// ID of the alert child 
    #define	HUM_ID 2 	//ID of the humidity child
    #define TEMP_ID 3 	//ID of the temp child
    
    #define BUTTON_PIN 2  				//Pin for the on/off button 
    // Set this to the pin you connected the DHT's data pin to
    #define DHT_DATA_PIN A0
    // Set this offset if the sensor has a permanent small offset to the real temperatures
    #define SENSOR_TEMP_OFFSET 0
    static const uint64_t UPDATE_INTERVAL = 60000;
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
    // the value didn't change since;
    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    #define FAN_RELAY_PIN  A1  			//Pin number for relay that will control the fan
    #define COVER_CLOSE_LIMIT_PIN A2 	//Pin number for the "cover closed" limit switch
    #define COVER_OPEN_LIMIT_PIN A3 	//Pin number for the "cover open" limit switch
    #define COVER_CLOSE_PIN A4 			//Pin number for the "cover close" L298N motor control board
    #define COVER_OPEN_PIN A5			//Pin number for the "cover open" L298N motor control board
    #define FAN_POWER_PIN A6			//Pin number for the ACS712 monitoring the fan
    #define COVER_POWER_PIN A7			//Pin number for the ACS712 monitoring the cover motor
    
    #define TFT_DISPLAY_ON //Use to turn on/off display functionality (need to turn off for debugging because code is too large).
    
    #ifdef TFT_DISPLAY_ON
    // TFT display and SD card pins.  They will share the software SPI interface.
    #define SPI_SCK 8  //Also can be labeled CLK on display
    #define SPI_DI  4 //Labeled MISO on display
    #define SPI_DO  7  //Labeled MOSI on display
    //#define SD_CS   5  // Chip select line for SD card (not currently used)
    #define TFT_CS  3
    #define TFT_DC  6 //Labeled RS
    #define TFT_RST 0  // you can also connect this to the Arduino reset
    Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, SPI_DO, SPI_SCK, TFT_RST);
    #endif
    
    #define DEBUG_ON   // comment out to supress serial monitor output
    
    #ifdef DEBUG_ON
    #define DEBUG_PRINT(x)   Serial.print(x)
    #define DEBUG_PRINTLN(x) Serial.println(x)
    #define SERIAL_START(x)  Serial.begin(x)
    #else
    #define DEBUG_PRINT(x)
    #define DEBUG_PRINTLN(x)
    #define SERIAL_START(x)
    #endif
    
    #define RELAY_ON 1 //Switch to 0 if fan relay is off when it should be on
    #define RELAY_OFF 0 //Switch to 1 if fan relay is on when it should be off
    #define DWELL_TIME 50 //Time to wait between radio messages sent (helps prevent missed messages)
    #define closingStall 465 //The value of the ACS712 when the cover motor is stopped while closing. This value should be less than the normal operating power draw.
    #define openingStall 580 //The value of the ACS712 when the cover motor is stopped while opening.  This value should be greater than the normal operating power draw.
    #define coverLimitTime 37000 //Slightly over the time it takes for the cover to fully open/close in milliseconds.  This will prevent the cover motor from running indefinitely.
    
    //Fan power reading variables. You may need to adjust these depending on your ACS712 model and house voltage
    uint8_t mVperAmp = 69; //had to adjust for my sensor you may need to adjust yours a well // use 185 for 5A Module, 100 for 20A Module and 66 for 30A Module
    uint8_t houseVoltage = 220; //Voltage of your house wiring (110 or 220) 
    
    Bounce debouncerOnOff = Bounce();
    Bounce debouncerClosedState = Bounce();
    Bounce debouncerOpenState = Bounce();
    uint8_t fanButtonPrev = 0;
    uint8_t fanState = 0;
    uint8_t fanStatePrevious = 1;
    uint8_t fanRelayState;
    uint8_t coverMoving = 0;
    uint8_t	coverClosedState = LOW;
    uint8_t	coverOpenState = LOW;
    uint8_t errorState = 0; //Used to keep track of errors.  Can be reset by manually pushing button
    uint8_t fanPowerReading = 0;
    int coverPowerReading = 0;
    unsigned long currentMillis; //used for timers
    unsigned long powerReadMillis; //Used read power every second
    unsigned long powerUpdateMillis; //Used to update power usage on LCD and gateway
    unsigned long coverMillis;
    unsigned long dhtMillisPrev;
    unsigned long dhtDelay = 305000;	//5 minutes 5 seconds.  Offset is in case of power failure I don't want all my nodes reporting at the same time.
    unsigned long lastGetTime; //Used for getting time from gateway
    
    uint8_t lastSecond;
    uint8_t lastMinute;
    uint8_t lastHour;
    
    DHT dht;
    float lastTemp = 0;
    float lastHum = 0;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    boolean metric = true; //Set to true if you use the metric system
    
    //Fan power reading variables.
    double Voltage = 0; //Voltage read from analog pin (used to calc power)
    double VRMS = 0;
    double AmpsRMS = 0;
    uint16_t wattTotal = 0; //Used to calculate the watts used for the last minute
    int wattAvg = 0;
    int wattAvgPrev = 0;
    uint8_t wattCount = 0; //Will be used to divide watts
    uint16_t pMaxValue = 0; // store max value here
    uint16_t pMinValue = 1024; // store min value here
    
    
    //MySensor gw;
    MyMessage msgFan(FAN_ID, V_STATUS);
    MyMessage msgFanPwr(FAN_ID, V_WATT);
    MyMessage msgError(ERROR_ID, V_TRIPPED);
    MyMessage msgHum(HUM_ID, V_HUM);
    MyMessage msgTemp(TEMP_ID, V_TEMP);
    
    void presentation()  
    { 
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
      present(FAN_ID, S_BINARY);
      wait(DWELL_TIME);
      present(ERROR_ID, S_MOTION);
      wait(DWELL_TIME);
      present(HUM_ID, S_HUM);
      wait(DWELL_TIME);
      present(TEMP_ID, S_TEMP);
      wait(DWELL_TIME);
      metric = getConfig().isMetric;
    }
    
    void setup()
    {
      delay(2000); //Allow time for sensors to power up
      
    requestTime();
      // Send the sketch version information to the gateway and Controller
    
    
      dht.setup(DHT_DATA_PIN);
        if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
        Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
      }
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      sleep(dht.getMinimumSamplingPeriod());
    
      // Make sure relays are off when starting up
      digitalWrite(FAN_RELAY_PIN, RELAY_OFF);
      digitalWrite(COVER_OPEN_PIN, LOW);
      digitalWrite(COVER_CLOSE_PIN, LOW);
    
      // Set the pin mode
      pinMode(FAN_RELAY_PIN, OUTPUT);
      pinMode(COVER_OPEN_PIN, OUTPUT);
      pinMode(COVER_CLOSE_PIN, OUTPUT);
      pinMode(COVER_OPEN_LIMIT_PIN, INPUT_PULLUP);
      pinMode(COVER_CLOSE_LIMIT_PIN, INPUT_PULLUP);
      pinMode(BUTTON_PIN, INPUT_PULLUP); // Setup the on/off button and activate internal pull-up
    
      // After setting up the pin modes, setup debouncers
      debouncerOnOff.attach(BUTTON_PIN);
      debouncerOnOff.interval(50);
      debouncerOpenState.attach(COVER_OPEN_LIMIT_PIN);
      debouncerOpenState.interval(50);
      debouncerClosedState.attach(COVER_CLOSE_LIMIT_PIN);
      debouncerClosedState.interval(50);
    
      // Register all sensors to gw (they will be created as child devices)
    
    
      send(msgError.set(0)); // Reset Alert state
    
      //Check the cover slide limit switch values
      debouncerOpenState.update();
      coverOpenState = debouncerOpenState.read();
    
      debouncerClosedState.update();
      coverClosedState = debouncerClosedState.read();
    
      metric = getConfig().isMetric;
    
    unsigned long functionTimeout = millis();
      while (timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL)
      {
        requestTime(); 
        DEBUG_PRINTLN(F("Getting Time"));
        wait(1000); // call once per second
        DEBUG_PRINTLN(F("."));
      }
    
    #ifdef TFT_DISPLAY_ON
      //**Note: I had a red tab LCD but the black tab setting worked the best for me
      // If your TFT's plastic wrap has a Black Tab, use the following:
      tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
      // If your TFT's plastic wrap has a Red Tab, use the following:
      //tft.initR(INITR_REDTAB);   // initialize a ST7735R chip, red tab
      // If your TFT's plastic wrap has a Green Tab, use the following:
      //tft.initR(INITR_GREENTAB); // initialize a ST7735R chip, green tab
    
      //Initial Setup - Set state to Idle
      tft.drawLine(0, 7, 160, 7, tft.Color565(123, 123, 123)); //Setup
      tft.fillRect(0, 8, 160, 21, tft.Color565(80, 80, 80)); //Setup
      tft.drawLine(0, 29, 160, 29, tft.Color565(34, 34, 34)); //Setup
      tft.drawLine(0, 110, 160, 110, ST7735_WHITE); //Setup
      tft.fillRect(0, 111, 160, 43, tft.Color565(230, 230, 230)); //Setup
      tft.drawLine(0, 153, 160, 153, tft.Color565(170, 170, 170)); //Setup
    
      updateTime();
      updateTemp();
      updateHum();
    
    #endif
    
      currentMillis = millis();
      coverMillis = currentMillis;
    
      //Make sure the fan is off and the cover is closed when first powered on
      fanOff();
    }
    
    
    void loop()
    {
      // Force reading sensor, so it works also after sleep()
      dht.readSensor(true);
      
      currentMillis = millis(); //Set the current millis (used for timers)
    
      //Check the cover slide limit switch values
      debouncerOpenState.update();
      coverOpenState = debouncerOpenState.read();
    
      debouncerClosedState.update();
      coverClosedState = debouncerClosedState.read();
      //  DEBUG_PRINT(F("coverClosedState = "));
      //  DEBUG_PRINTLN(coverClosedState);
    
      //There is a spike in current when the motor is first turned on.  We need to stop reading for a short period so the motor doesn't immedately turn off
      if (currentMillis - coverMillis > 1500)
      {
        coverPowerReading = analogRead(COVER_POWER_PIN); //change back when sensor is attached
        //DEBUG_PRINT(F("coverPowerReading = "));
        //DEBUG_PRINTLN(coverPowerReading);
        if (coverPowerReading > closingStall && coverPowerReading < openingStall)
        {
          //Cover motor power draw is within limits
          coverPowerReading = 0;
        }
        else
        {
          //Cover motor power draw is over the limit.  Motor has stalled.
          coverPowerReading = 1;
        }
      }
    
      debouncerOnOff.update();
      uint8_t fanButton = debouncerOnOff.read(); // Get the update value
      //DEBUG_PRINTLN(fanButton);
      if (fanButton != fanButtonPrev && fanButton == 0) {
        if (coverMoving == 1)
        {
          //If the cover is already moving, change directions.
          fanStatePrevious = fanState;
          coverMoving = 0;
        }
        fanState = fanState ? 0 : 1;
        DEBUG_PRINT(F("fanState value changed to: "));
        DEBUG_PRINTLN(fanState);
        send(msgFan.set(fanState), true); // Send new state and request ack back
        errorState = 0;
        wait(DWELL_TIME);
        send(msgError.set(0)); // Reset Alert state
        coverMillis = currentMillis; //Set the millis (used to keep track of cover close/open times)
      }
      fanButtonPrev = fanButton;
    
      if (fanState != fanStatePrevious && fanState == 0 && errorState == 0)
      {
        fanOff();
      }
      if (fanState != fanStatePrevious && fanState == 1 && errorState == 0)
      {
        fanOn();
      }
    
      if (currentMillis - dhtMillisPrev > dhtDelay)
      {
        float temperature = dht.getTemperature();
    
        if (isnan(temperature))
        {
          DEBUG_PRINTLN(F("Failed reading temperature from DHT"));
        }
        else
        {
          if (!metric)
          {
            temperature = dht.toFahrenheit(temperature);
          }
          if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS)
          {
            lastTemp = temperature;
            send(msgTemp.set(temperature, 1));
            wait(DWELL_TIME);
    #ifdef TFT_DISPLAY_ON
            updateTemp();
    #endif
            DEBUG_PRINT(F("Temperature is: "));
            DEBUG_PRINTLN(temperature);
          }
        }
        float humidity = dht.getHumidity();;
        if (isnan(humidity))
        {
          DEBUG_PRINTLN(F("Failed reading humidity from DHT"));
        } else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS)
        {
          lastHum = humidity;
          nNoUpdatesHum = 0;
          send(msgHum.set(humidity, 1));
          wait(DWELL_TIME);
    #ifdef TFT_DISPLAY_ON
          updateHum();
    #endif
    
          DEBUG_PRINT(F("Humidity is: "));
          DEBUG_PRINTLN(humidity);
        } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
        dhtMillisPrev = currentMillis;
      }
    
      /*
        Check power usage here
        I want to check it every second then send it every minute (when changed) to the gateway and LCD
        In the "every second" check it should get a running average so it would divide by the number of seconds
      */
    
      if (currentMillis - powerReadMillis < 1000)
      {
        //Read power every second
        uint16_t readValue = analogRead(FAN_POWER_PIN);
        //DEBUG_PRINT(F("readValue: "));
        //DEBUG_PRINTLN(readValue);
    
        // see if you have a new pMaxValue
        if (readValue > pMaxValue)
        {
          /*record the maximum sensor value*/
          pMaxValue = readValue;
        }
        if (readValue < pMinValue)
        {
          /*record the maximum sensor value*/
          pMinValue = readValue;
        }
      }
      else
      {
        //Calulate power usage and update gateway if necessary
        // Subtract min from max
        Voltage = ((pMaxValue - pMinValue) * 5.0) / 1024.0;
        VRMS = (Voltage / 2.0) * 0.707;
        AmpsRMS = (VRMS * 1000) / mVperAmp;
    
        if (AmpsRMS < .15) //filter out low readings when fan is off
        {
          AmpsRMS = 0;
        }
        DEBUG_PRINT(F("Amps RMS: "));
        DEBUG_PRINT(AmpsRMS);
    
        wattTotal += houseVoltage * AmpsRMS;
        DEBUG_PRINT(F(".  Watt Total: "));
        DEBUG_PRINT(wattTotal);
        wattCount ++;
        DEBUG_PRINT(F(".  Watt Count: "));
        DEBUG_PRINTLN(wattCount);
        powerReadMillis = currentMillis;
        //Reset max and min values
        pMaxValue = 0;
        pMinValue = 1024;
    
        //Update fanPowerReading to make sure the fan is off before closing the cover
        fanPowerReading = AmpsRMS > 1 ? 1 : 0;
        DEBUG_PRINT(F("fanPowerReading: "));
        DEBUG_PRINTLN(fanPowerReading);
    
        //Update Gateway and LCD every minute if necessary
        if (currentMillis - powerUpdateMillis > 60000)
        {
          //We don't want to flood the gateway with updates so if the last reading was close to the current one we don't need to send the new reading
          wattAvg = wattTotal / wattCount;
          DEBUG_PRINT(F("Watt Average: "));
          DEBUG_PRINTLN(wattAvg);
    
          //Only update if last usage was different by 2 watts
          if (wattAvgPrev - wattAvg > 2 || wattAvg - wattAvgPrev > 2)
          {
            //Send to gateway
            send(msgFanPwr.set(wattAvg));
    
    #ifdef TFT_DISPLAY_ON
            if (fanPowerReading == 1)
            {
              //Update LCD if running
              tft.setTextColor(ST7735_WHITE, tft.Color565(53, 47, 125));
              tft.setFont();
              tft.setTextSize(1);
              tft.setCursor(5, 95);
              tft.print("Watts: "); //First line of text 20 characters max
              tft.print(wattAvg);
              tft.print("  ");
              DEBUG_PRINT(F("Watts update display: "));
              DEBUG_PRINTLN(wattAvg);
            }
    
    
    #endif
    
          }
          wattAvgPrev = wattAvg;
    
          //Reset watt trackers
          wattTotal = 0;
          wattCount = 0;
    
          powerUpdateMillis = currentMillis;
    
          //Using this if statement to update the time every minute
    #ifdef TFT_DISPLAY_ON
          //Update Time on Display every minute
          updateTime();
    #endif
        }
      }
    
      if (currentMillis - lastGetTime >= 3600000UL) // updates clock time and gets zone times from gateway once every hour
      {
        DEBUG_PRINTLN(F("Requesting time and valve data from Gateway..."));
    
        lastGetTime = millis();
      }
    }
    
    void fanOff() {
      /*
         1. Turn off the fan
         2. Make sure it's off before we start closing the cover
         3. Close cover
            a. Start a timer for how long the closing should take
            b. Stop the motor when the limit switch is hit
         4. Ensure the limit switch has been pressed and the timer didn't run out.  If it did send an error message (via motion sensor).
         5. Send "off" message to gateway/controller
      */
    
      //DEBUG_PRINTLN(F("In the fanOff function"));
      if (fanRelayState == RELAY_ON)
      {
        DEBUG_PRINTLN(F("Turning off fan"));
        //Turn off fan and set fan relay state to 0
        digitalWrite(FAN_RELAY_PIN, RELAY_OFF);
        fanRelayState = RELAY_OFF;
    
      }
      if (currentMillis - coverMillis < coverLimitTime)
      {
        if (coverPowerReading == 0)
        {
          //Make sure the fan is off before closing the cover to prevent damage to the cover and fan
          if (fanPowerReading == 0)
          {
            //Start closing the cover
            //Set the close pin on the L298N board to high
    
            if (coverMoving == 0)
            {
              DEBUG_PRINTLN(F("Closing Cover"));
              digitalWrite(COVER_CLOSE_PIN, HIGH);
              //Set COVER_OPEN_PIN to low just to be safe
              digitalWrite(COVER_OPEN_PIN, LOW);
    
              //Update the LCD with "Closing" status message
    #ifdef TFT_DISPLAY_ON
              tft.setTextColor(ST7735_WHITE, tft.Color565(53, 47, 125));
              tft.setFont();
              tft.setTextSize(1);
              tft.setCursor(5, 95);
              tft.print("CLOSING COVER     "); //First line of text 20 characters max
    #endif
              coverMoving = 1;
            }
    
            if (coverClosedState == LOW)
            {
              //The cover is closed.  Stop motor and send status to gateway.
              digitalWrite(COVER_CLOSE_PIN, LOW);
              fanStatePrevious = fanState;
              send(msgFan.set(fanState), true); // Send new state with Ack
              coverMoving = 0;
    
    #ifdef TFT_DISPLAY_ON
              //Update LCD
              wait(200); //Wait for radio SPI to stop (otherwise display is garbled)
              updateTFTStatus(0); //Set status to idle state
    #endif
            }
          }
        }
        else
        {
          //Cover motor is using too much power.  Stop everything to avoid damage.
          DEBUG_PRINTLN(F("The slide motor is using too much power!"));
          digitalWrite(COVER_CLOSE_PIN, LOW);
          digitalWrite(COVER_OPEN_PIN, LOW);
          errorState = 1; //Set the error state so it doesn't keep trying to close
          send(msgError.set(1)); // Send alert state to gateway
    #ifdef TFT_DISPLAY_ON
          //Update LCD
          updateTFTStatus(2); //Set status to error state
          errorOvercurrent(); //More detailed error message
    #endif
        }
      }
      else
      {
        /*Things have taken too long there must be an error.  Print it out to the LCD and send trigger to gateway
          Possible errors could be:
          Fan did not shut off.
          Cover did not fully close in time (slide jam, motor slip etc.)
          Over current in cover motor (jammed?)
        */
        //Send commands to stop everything to avoid damage.
        DEBUG_PRINTLN(F("Cover time exceeded"));
        digitalWrite(FAN_RELAY_PIN, RELAY_OFF);
        digitalWrite(COVER_CLOSE_PIN, LOW);
        digitalWrite(COVER_OPEN_PIN, LOW);
        errorState = 1; //Set the error state so it doesn't keep trying to close
        send(msgError.set(1)); // Send alert state to gateway
    
    #ifdef TFT_DISPLAY_ON
        //Update LCD
        updateTFTStatus(2); //Set status to error state
        errorTime(); //Write more detailed error to LCD
    #endif
      }
    }
    
    void fanOn() {
    
      /*
        1. Open the cover
          a. Start a timer to keep track of how long the cover has been opening 
          b. Stop the motor when the limit switch is hit
        2. Ensure the limit switch has been pressed and the timer didn't run out.  If it did send an error message.
        3. Start the fan
        4. Send "on" message to gateway/controller
      */
    
      if (currentMillis - coverMillis < coverLimitTime)
      {
        if (coverPowerReading == 0)
        {
          //Start opening the cover
          if (coverMoving == 0)
          {
            DEBUG_PRINTLN(F("Opening Cover"));
    
            //Set COVER_CLOSE_PIN to low just to be safe
            digitalWrite(COVER_CLOSE_PIN, LOW);
            digitalWrite(COVER_OPEN_PIN, HIGH);
            coverMoving = 1;
    
    #ifdef TFT_DISPLAY_ON
            wait(200); //Wait for radio communication to stop (otherwise display is garbled because of SPI conflicts)
            //Update LCD
            updateTFTStatus(1); //Set status to idle state
    #endif
    
          }
    
          if (coverOpenState == LOW)
          {
            //The cover is open.  Stop motor and send status to gateway.
            digitalWrite(COVER_OPEN_PIN, LOW);
            fanStatePrevious = fanState;
            //Turn on Fan
            digitalWrite(FAN_RELAY_PIN, RELAY_ON);
            fanRelayState = RELAY_ON;
            coverMoving = 0;
          }
        }
        else
        {
          //Cover motor is using too much power.  Stop everything to avoid damage.
          DEBUG_PRINTLN(F("The cover motor is using too much power!"));
          digitalWrite(COVER_CLOSE_PIN, LOW);
          digitalWrite(COVER_OPEN_PIN, LOW);
          errorState = 1; //Set the error state so it doesn't keep trying to close
          send(msgError.set(1)); // Send alert state to gateway
    #ifdef TFT_DISPLAY_ON
          //Update LCD
          updateTFTStatus(2); //Set status to error state
          errorOvercurrent(); //More detailed error message
    #endif
        }
      }
      else
      {
        /*Things have taken too long there must be an error.  Print it out to the LCD and send trigger to gateway
          Possible errors could be:
          Cover did not fully open in time (slide jam, motor slip etc.)
          Overcurrent in cover motor (jammed?)
        */
        //Send commands to stop everything to avoid damage.
        DEBUG_PRINTLN(F("Cover time exceeded"));
        digitalWrite(COVER_CLOSE_PIN, LOW);
        digitalWrite(COVER_OPEN_PIN, LOW);
        errorState = 1; //Set the error state so it doesn't keep trying to close
    
    #ifdef TFT_DISPLAY_ON
        //Update LCD
        updateTFTStatus(2); //Set status to error state
        tft.setCursor(5, 90);
        //More detailed error message
        errorTime();
    #endif
      }
    
    }
    
    
    void receive(const MyMessage & message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.isAck()) {
        DEBUG_PRINTLN(F("This is an ack from gateway"));
      }
    
      if (message.type == V_LIGHT && !message.isAck()) {
        // Change relay state
        fanState = message.getBool();
        if (coverMoving == 1)
        {
          //If the cover is already moving, check to see if we need to change directions
          DEBUG_PRINT(F("Cover is moving"));
          if (fanState == fanStatePrevious)
          {
            //We need to change directions
            fanStatePrevious = fanState ? 0 : 1;
            coverMoving = 0;
          }
        }
        coverMillis = millis(); //Set the millis (used to keep track of cover close/open times)
    
        // Write some debug info
        DEBUG_PRINT(F("Incoming change for sensor:"));
        DEBUG_PRINT(message.sensor);
        DEBUG_PRINT(F(", New status: "));
        DEBUG_PRINTLN(fanState);
      }
    }
    
    // This is called when a new time value was received
    void receiveTime(unsigned long time) {
      // Ok, set incoming time 
      setTime(time);
    }
    
    #ifdef TFT_DISPLAY_ON
    void updateTFTStatus(uint8_t bgStat)
    {
      //bgStat: 0 = "Idle", 1 = "Running", 2 = "Error"
      //Idle Color = 37, 125, 20
      //Running Color = 53, 47, 125
      //Error Color = 155, 26, 26
    
      uint8_t r, g, b;
      const char *displayStatus[] = {
        "Idle", "Running", "Error"
      };
      if (bgStat == 0)
      {
        //Idle
        r = 37;
        g = 125;
        b = 20;
      }
      else if (bgStat == 1)
      {
        //Running
        r = 53;
        g = 47;
        b = 125;
      }
      else
      {
        //Error
        r = 155;
        g = 26;
        b = 26;
      }
    
      tft.fillRect(0, 0, 160, 7, tft.Color565(r, g, b));
      tft.fillRect(0, 30, 160, 80, tft.Color565(r, g, b));
      tft.fillRect(0, 154, 160, 6, tft.Color565(r, g, b));
    
      tft.setCursor(5, 40);
      tft.setTextColor(ST7735_WHITE);
      tft.setTextSize(1);
      tft.println("Status");
    
      tft.setCursor(5, 65);
      tft.setTextColor(ST7735_WHITE);
      tft.setFont();
      //tft.setTextSize(3);
      tft.setTextSize(bgStat == 1 ? 2 : 3); //The word "Running" doesn't fit with text size 3.
      tft.println(displayStatus[bgStat]);
    
    }
    void errorOvercurrent()
    {
      tft.setCursor(5, 90);
      tft.setTextColor(ST7735_WHITE);
      tft.setFont();
      tft.setTextSize(1);
      tft.println("Motor overcurrent"); //First line of text 20 characters max
      tft.setCursor(5, 101);
      tft.println("Check cover slide"); //Second line of text 20 characters max
    }
    void errorTime()
    {
      tft.setCursor(5, 90);
      tft.setTextColor(ST7735_WHITE);
      tft.setFont();
      tft.setTextSize(1);
      tft.println("Time exceeded"); //First line of text 20 characters max
      tft.setCursor(5, 100);
      tft.println("Check cover slide"); //Second line of text 20 characters max
    }
    void updateTime()
    {
      //Update Time
      tft.setCursor(5, 17);
      tft.setTextColor(ST7735_WHITE, tft.Color565(80, 80, 80));
      tft.setTextSize(1);
      tft.print(hourFormat12());
      tft.print(minute() < 10 ? F(":0") : F(":"));
      tft.print(minute());
      tft.print(isAM() ? F("am") : F("pm"));
      tft.print(month() < 10 ? F(" 0") : F(" "));
      tft.print(month());
      tft.print(day() < 10 ? F("/0") : F("/"));
      tft.print(day());
      tft.print(F("/"));
      tft.print(year() % 100);
      tft.print(F(" "));
    }
    void updateTemp()
    {
      //Update Temperature
      tft.setCursor(5, 120);
      tft.setTextColor(tft.Color565(80, 80, 80), tft.Color565(230, 230, 230));
      tft.setTextSize(1);
      tft.print("Temp: ");
      tft.print(lastTemp, 1);
      tft.print((char)247);
      tft.print(" ");
    }
    void updateHum()
    {
      //Update Humidity
      tft.setCursor(5, 140);
      tft.setTextColor(tft.Color565(80, 80, 80), tft.Color565(230, 230, 230));
      tft.setTextSize(1);
      tft.print("Humidity: ");
      tft.print(lastHum, 1);
      tft.print("% ");
    }
    #endif
    


  • This is the output that i get. Maybe you can understand why. And this is a clean example. Anyone have make temp DHT11 to work in version2 ?

    Starting sensor (RNNNA-, 2.0.0)
    TSM:INIT
    TSM:RADIO:OK
    TSP:ASSIGNID:OK (ID=27)
    TSM:FPAR
    TSP:MSG:SEND 27-27-255-255 s=255,c=3,t=7,pt=0,l=0,sg=0,ft=0,st=bc:
    TSM:FPAR
    TSP:MSG:SEND 27-27-255-255 s=255,c=3,t=7,pt=0,l=0,sg=0,ft=0,st=bc:
    TSP:MSG:READ 25-25-27 s=255,c=3,t=8,pt=1,l=1,sg=0:1
    TSP:MSG:FPAR RES (ID=25, dist=1)
    TSP:MSG:PAR OK (ID=25, dist=2)
    TSP:MSG:READ 0-0-27 s=255,c=3,t=8,pt=1,l=1,sg=0:0
    TSP:MSG:FPAR RES (ID=0, dist=0)
    TSP:MSG:PAR OK (ID=0, dist=1)
    TSM:FPAR:OK
    TSM:ID
    TSM:CHKID:OK (ID=27)
    TSM:UPL
    TSP:PING:SEND (dest=0)
    TSP:MSG:SEND 27-27-0-0 s=255,c=3,t=24,pt=1,l=1,sg=0,ft=0,st=ok:1
    TSP:MSG:READ 0-0-27 s=255,c=3,t=25,pt=1,l=1,sg=0:1
    TSP:MSG:PONG RECV (hops=1)
    TSP:CHKUPL:OK
    TSM:UPL:OK
    TSM:READY
    TSP:MSG:SEND 27-27-0-0 s=255,c=3,t=15,pt=6,l=2,sg=0,ft=0,st=ok:0100
    TSP:MSG:SEND 27-27-0-0 s=255,c=0,t=17,pt=0,l=5,sg=0,ft=0,st=ok:2.0.0
    TSP:MSG:SEND 27-27-0-0 s=255,c=3,t=6,pt=1,l=1,sg=0,ft=0,st=ok:0
    TSP:MSG:READ 0-0-27 s=255,c=3,t=15,pt=6,l=2,sg=0:0100
    TSP:MSG:READ 0-0-27 s=255,c=3,t=6,pt=0,l=1,sg=0:M
    TSP:MSG:SEND 27-27-0-0 s=255,c=3,t=11,pt=0,l=22,sg=0,ft=0,st=ok:TemperatureAndHumidity
    TSP:MSG:SEND 27-27-0-0 s=255,c=3,t=12,pt=0,l=3,sg=0,ft=0,st=ok:1.1
    TSP:MSG:SEND 27-27-0-0 s=0,c=0,t=7,pt=0,l=0,sg=0,ft=0,st=ok:
    TSP:MSG:SEND 27-27-0-0 s=1,c=0,t=6,pt=0,l=0,sg=0,ft=0,st=ok:
    Request registration...
    TSP:MSG:SEND 27-27-0-0 s=255,c=3,t=26,pt=1,l=1,sg=0,ft=0,st=ok:2
    TSP:MSG:READ 0-0-27 s=255,c=3,t=27,pt=1,l=1,sg=0:1
    Node registration=1
    Init complete, id=27, parent=0, distance=1, registration=1```
    

    If i get the sensor out i get this

    Init complete, id=27, parent=0, distance=1, registration=1
    Failed reading temperature from DHT!
    Failed reading humidity from DHT
    

  • Admin

    @rechin304 Something is most likely wrong with your wiring or the sensor. I am using a DHT22 without any issues in my rain gauge which is on 2.0 (I'm using the most recent beta release). Try connecting a 4.7k resistor between the data pin and power on the DHT like this.
    0_1478303148400_upload-1d245d6b-aad9-4841-8307-485c9caf5056



  • @petewill wow, your screen case looks amazing! Is that acryl glass? Did you build that yourself too?


  • Admin

    @enlo Thanks. Yeah, it's acrylic glass (Plexiglas). It was a pain to use though as I couldn't clean off the paint very well. My next project I'm working on I'm going to try to use regular glass.



  • @rechin304 said:

    dht.setup(DHT_DATA_PIN);
    if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
    Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
    }
    // Sleep for the time of the minimum sampling period to give the sensor time to power up
    // (otherwise, timeout errors might occure for the first reading)
    sleep(dht.getMinimumSamplingPeriod());

    For what it's worth, I just went through a very long debug session trying to get a simple dht11 based sensor built and working. For reasons I don't even pretend to understand, the one thing I changed that allows it to work is changing the 'sleep' command in this section of the setup function to a 'wait' command.



  • @flyswiftly thanks for trying,

    in my case still i do not see any data. What library do you use ? The one from MySensorsArduinoExamples-master.zip ?



  • @rechin304

    What library do you use ? The one from MySensorsArduinoExamples-master.zip ?

    Actually, no. It turns out when I looked through my IDE that I am using the prior version of the DHT library. That did also force me to comment out the read sensor line just to make it compile. Maybe the combination of the two changes is what does the trick. I hadn't made those changes together, so I missed the possible significance of this change:

    void loop()      
    {  
      // Force reading sensor, so it works also after sleep()
    //  dht.readSensor(true);
    
    

    Running a diff on both the library you point out and the one I'm using shows that adding that bool to the readSendor function is the only code difference.



  • @flyswiftly
    I also did that try an older version library for DHT and receive data. So conclusion is that on current (latest) DHT library for DHT11 is not working. Now I'm on a business trip to China for a week and With this chance i will buy there DHT 22 to be sure. I will be back in a week with conclusion.



  • I can confirm that DHT library that is in example do not work with DHT11 and DHT22 in my case, using other (older) library i can see data.


  • Admin

    @rechin304 Sorry, just to make sure I understand, are you saying it works with a DHT22 or not? I may still be on an old library too.



  • @petewill
    Works with DHT22 and other library (old one). I could not make it work withe one from example.

    I'm almost ready with build, waiting for final pieces. hope to receive them this week.
    one more ting i noticed is that clock is behind with 2minutes, so i need to check the code again.



  • I have an working prototype, see video https://goo.gl/photos/VSQeaevHh7UbbStr9
    Many thanks to @petewill for his work and inspiration.
    I will post final pictures when ready.



  • Added new lead screw pitch of 2Mm that decrease open/close time from 3 minutes to 40 sec. see pics https://goo.gl/photos/mQvF1S9FrdNYPpdH9

    buyed from here http://www.ebay.com/itm/322139119923?_trksid=p2057872.m2749.l2649&var=511054006707&ssPageName=STRK%3AMEBIDX%3AIT
    for who is interested.


  • Admin

    @rechin304 Awesome! Glad you got it working!!



  • @petewill Hi Pete
    Just Start building the system and got an error at sketch verify.
    "exit status 1
    'class Adafruit_ST7735' has no member named 'setFont'"


  • Admin

    @lis610 Sorry for the delay. Work has been very busy. I have attached the libraries I'm using. I was able to get it to compile when I just tested. https://drive.google.com/file/d/1wauxHRf5pyqLnBGsfCP8UPJQR1wNdkoF/view?usp=sharing

    Let me know if you have issues with this.



  • THANK YOU so much for sharing. Most of the errors gone, but one left (using Arduino v.1.8.5; MySensors v 2.3.0):
    [C:\Users\BEAST\Documents\Arduino\Whole-House-Fan\code\New folder\WholeHouseFan2.0\WholeHouseFan2.0.ino: In function 'void presentation()':
    WholeHouseFan2.0:197: error: 'TEMP_CHILD_NAME' was not declared in this scope present(TEMP_ID, S_TEMP, TEMP_CHILD_NAME);
    exit status 1]
    'TEMP_CHILD_NAME' was not declared in this scope


  • Admin

    @lis610 Sorry about that. I just fixed the code on the build page. Hopefully that will get you up and running 🙂



  • Thank you. Did you upload the file for download?


  • Admin

    @lis610 yes, I uploaded it to the page in the link at the top of this page.



  • Cannot locate file "WholeHouseFan2.0.ino"


  • Admin

    @lis610 Strange. It disappeared. I added it again and just downloaded it so you should be good. Sorry for all the issues!



  • Thank you. The box is ready. Next step connect all hardware. So far no luck with the display (KMR-1.8 SPI). What kind of display model you used in this project.


  • Admin



  • Got the same display. It is working with Adafruit graphicstest example. I did not connect any components just display. If I ran the FAN sketch should be something showing on the display?
    Or need to connect everything?


  • Admin

    @lis610 is #define TFT_DISPLAY_ON uncommented? Also, you will at least need the radio attached so the MySensors code can fully load (you can also setup defines to proceed without connecting to gateway but I don't remember them off the top of my head). I don't remember if there are any other dependencies since it as been so long since I built this.



  • Please help
    Display is working with Adafruit graphicstest example pins:
    #define TFT_CS 10 #define TFT_RST 9 #define TFT_DC 8# define TFT_SCLK 13 #define TFT_MOSI 11
    I did try the same pins in FAN sketch -nothing on display
    Tryed pin# from FAN sketch on Adafruit graphicstest- nothing on display.
    Nothing come up
    I did connect to the radio. Got something from MY_DUBUG not sure is it good or bad:

    624893 TSF:MSG:SEND,5-5-255-255,s=255,c=3,t=7,pt=0,l=0,sg=0,ft=1,st=OK:
    626903 !TSM:FPAR:NO REPLY
    626905 TSM:FPAR
    626941 TSF:MSG:SEND,5-5-255-255,s=255,c=3,t=7,pt=0,l=0,sg=0,ft=0,st=OK:
    628951 !TSM:FPAR:NO REPLY
    628953 TSM:FPAR
    628989 TSF:MSG:SEND,5-5-255-255,s=255,c=3,t=7,pt=0,l=0,sg=0,ft=0,st=OK:
    630999 !TSM:FPAR:NO REPLY
    631001 TSM:FPAR
    631037 TSF:MSG:SEND,5-5-255-255,s=255,c=3,t=7,pt=0,l=0,sg=0,ft=0,st=OK:
    633047 !TSM:FPAR:FAIL
    633049 TSM:FAIL:CNT=7
    633051 TSM:FAIL:DIS
    633053 TSF:TDI:TSL
    693057 TSM:FAIL:RE-INIT
    693059 TSM:INIT

    693067 TSM:INIT:TSP OK
    693069 TSF:SID:OK,ID=5
    693071 TSM:FPAR
    693108 TSF:MSG:SEND,5-5-255-255,s=255,c=3,t=7,pt=0,l=0,sg=0,ft=0,st=OK:
    693432 TSF:MSG:READ,0-0-5,s=255,c=3,t=8,pt=1,l=1,sg=0:0
    693438 TSF:MSG:FPAR OK,ID=0,D=1
    695117 TSM:FPAR:OK
    695119 TSM:ID
    695119 TSM:ID:OK
    695121 TSM:UPL
    695160 !TSF:MSG:SEND,5-5-0-0,s=255,c=3,t=24,pt=1,l=1,sg=0,ft=0,st=NACK:1
    697171 TSM:UPL
    697178 TSF:MSG:SEND,5-5-0-0,s=255,c=3,t=24,pt=1,l=1,sg=0,ft=1,st=OK:1
    699187 TSM:UPL
    699224 !TSF:MSG:SEND,5-5-0-0,s=255,c=3,t=24,pt=1,l=1,sg=0,ft=0,st=NACK:1
    701233 TSM:UPL


  • Admin

    @lis610 It looks like it's having issues communicating with your gateway. Here is a link to the log parser. You can use this in the future to check out your logs.

    https://www.mysensors.org/build/parser?log=624893 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D1%2Cst%3DOK%3A 626903 !TSM%3AFPAR%3ANO REPLY 626905 TSM%3AFPAR 626941 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D0%2Cst%3DOK%3A 628951 !TSM%3AFPAR%3ANO REPLY 628953 TSM%3AFPAR 628989 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D0%2Cst%3DOK%3A 630999 !TSM%3AFPAR%3ANO REPLY 631001 TSM%3AFPAR 631037 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D0%2Cst%3DOK%3A 633047 !TSM%3AFPAR%3AFAIL 633049 TSM%3AFAIL%3ACNT%3D7 633051 TSM%3AFAIL%3ADIS 633053 TSF%3ATDI%3ATSL 693057 TSM%3AFAIL%3ARE-INIT 693059 TSM%3AINIT 693067 TSM%3AINIT%3ATSP OK 693069 TSF%3ASID%3AOK%2CID%3D5 693071 TSM%3AFPAR 693108 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D0%2Cst%3DOK%3A 693432 TSF%3AMSG%3AREAD%2C0-0-5%2Cs%3D255%2Cc%3D3%2Ct%3D8%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A0 693438 TSF%3AMSG%3AFPAR OK%2CID%3D0%2CD%3D1 695117 TSM%3AFPAR%3AOK 695119 TSM%3AID 695119 TSM%3AID%3AOK 695121 TSM%3AUPL 695160 !TSF%3AMSG%3ASEND%2C5-5-0-0%2Cs%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cft%3D0%2Cst%3DNACK%3A1 697171 TSM%3AUPL 697178 TSF%3AMSG%3ASEND%2C5-5-0-0%2Cs%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cft%3D1%2Cst%3DOK%3A1 699187 TSM%3AUPL 699224 !TSF%3AMSG%3ASEND%2C5-5-0-0%2Cs%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cft%3D0%2Cst%3DNACK%3A1 701233 TSM%3AUPL

    Also, did you comment/uncomment the proper defines as noted above and in the code comments?

    Try adding this line before #include <MySensors.h>

    #define MY_TRANSPORT_WAIT_READY_MS 4000 //This will allow the sensor to function if it can't find the gateway when it first starts up
    


  • This my node:
    https://www.mysensors.org/build/parser?log=624893 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D1%2Cst%3DOK%3A 626903 !TSM%3AFPAR%3ANO REPLY 626905 TSM%3AFPAR 626941 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D0%2Cst%3DOK%3A 628951 !TSM%3AFPAR%3ANO REPLY 628953 TSM%3AFPAR 628989 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D0%2Cst%3DOK%3A 630999 !TSM%3AFPAR%3ANO REPLY 631001 TSM%3AFPAR 631037 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D0%2Cst%3DOK%3A 633047 !TSM%3AFPAR%3AFAIL 633049 TSM%3AFAIL%3ACNT%3D7 633051 TSM%3AFAIL%3ADIS 633053 TSF%3ATDI%3ATSL 693057 TSM%3AFAIL%3ARE-INIT 693059 TSM%3AINIT 693067 TSM%3AINIT%3ATSP OK 693069 TSF%3ASID%3AOK%2CID%3D5 693071 TSM%3AFPAR 693108 TSF%3AMSG%3ASEND%2C5-5-255-255%2Cs%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%2Cft%3D0%2Cst%3DOK%3A 693432 TSF%3AMSG%3AREAD%2C0-0-5%2Cs%3D255%2Cc%3D3%2Ct%3D8%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A0 693438 TSF%3AMSG%3AFPAR OK%2CID%3D0%2CD%3D1 695117 TSM%3AFPAR%3AOK 695119 TSM%3AID 695119 TSM%3AID%3AOK 695121 TSM%3AUPL 695160 !TSF%3AMSG%3ASEND%2C5-5-0-0%2Cs%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cft%3D0%2Cst%3DNACK%3A1 697171 TSM%3AUPL 697178 TSF%3AMSG%3ASEND%2C5-5-0-0%2Cs%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cft%3D1%2Cst%3DOK%3A1 699187 TSM%3AUPL 699224 !TSF%3AMSG%3ASEND%2C5-5-0-0%2Cs%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cft%3D0%2Cst%3DNACK%3A1 701233 TSM%3AUPL



  • Gateway :
    https://www.mysensors.org/build/parser?log=0%3B0%3B3%3B0%3B9%3Bgateway started%2C id%3D0%2C parent%3D0%2C distance%3D0 0%3B0%3B3%3B0%3B14%3BGateway startup complete. 0%3B0%3B3%3B0%3B9%3Bread and forward%3A 3-3-255 s%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%3A 0%3B0%3B3%3B0%3B9%3Bsend%3A 0-0-3-3 s%3D255%2Cc%3D3%2Ct%3D8%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cst%3Dok%3A0 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread and forward%3A 3-3-255 s%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%3A 0%3B0%3B3%3B0%3B9%3Bsend%3A 0-0-3-3 s%3D255%2Cc%3D3%2Ct%3D8%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cst%3Dfail%3A0 0%3B0%3B3%3B0%3B9%3Bread and forward%3A 3-3-255 s%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%3A 0%3B0%3B3%3B0%3B9%3Bsend%3A 0-0-3-3 s%3D255%2Cc%3D3%2Ct%3D8%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cst%3Dfail%3A0 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread and forward%3A 3-3-255 s%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%3A 0%3B0%3B3%3B0%3B9%3Bsend%3A 0-0-3-3 s%3D255%2Cc%3D3%2Ct%3D8%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cst%3Dok%3A0 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1 0%3B0%3B3%3B0%3B9%3Bread and forward%3A 3-3-255 s%3D255%2Cc%3D3%2Ct%3D7%2Cpt%3D0%2Cl%3D0%2Csg%3D0%3A 0%3B0%3B3%3B0%3B9%3Bsend%3A 0-0-3-3 s%3D255%2Cc%3D3%2Ct%3D8%2Cpt%3D1%2Cl%3D1%2Csg%3D0%2Cst%3Dfail%3A0 0%3B0%3B3%3B0%3B9%3Bread%3A 3-3-0 s%3D255%2Cc%3D3%2Ct%3D24%2Cpt%3D1%2Cl%3D1%2Csg%3D0%3A1 3%3B255%3B3%3B0%3B24%3B1



  • VeraEdge:
    0_1531501461806_11c53ac4-625a-4b5e-8e57-07c5c554f397-image.png
    0_1531501485787_c5088b75-3b8b-4d51-9fb4-fe73ea3918b2-image.png



  • Hi Pete,
    Do you see anything wrong with gateway, node and vera


  • Admin

    @lis610 sorry, I'm not a place where I can look in depth. It looks like your code isn't communicating with the gateway though. Did you try the line of code above? The device should work with the push button even if it can't communicate with the gateway (with that code).



  • I will come back to the communication issue later.
    In your resent code SPI is comment out " //#include <SPI.h> " what is the reason you comment SPI?
    The display is not showing anything even with: #define TFT_DISPLAY_ON. and #include <SPI.h>


  • Admin

    @lis610 if it can't communicate with the gateway and controller the node will never get to the loop which could be why the display isn't working. The SPI include used to be required for MySensors.



  • @lis610 It seems you have two problems.
    1 The radio is not connecting reliably with the gateway and may blocking the display from starting.
    There are lots of other messages on troubleshooting radio problems.

    2 The Graphic Display is not operating correctly.

    For Item one, You eventually need to resolve the radio problem, However as pete stated in his message if you add the following define it will allow the sketch to run, I can confirm this as i have just tested with just a arduino and just a graphics display.

    #define MY_TRANSPORT_WAIT_READY_MS 4000 //This will allow the sensor to function if it can't find the gateway when it first starts up
    

    So if you add this and the display still does not display then you need to test the display connections.

    You stated

    "Display is working with Adafruit graphicstest example pins:
    #define TFT_CS 10 #define TFT_RST 9 #define TFT_DC 8# define TFT_SCLK 13 #define TFT_MOSI 11
    I did try the same pins in FAN sketch -nothing on display
    Tryed pin# from FAN sketch on Adafruit graphicstest- nothing on display."

    So with standard connections the display is working.
    So you need to test and get the display working with the adafruit test program using the correct pins required for the house fan program.

    Add the following info the adafruit test sketch as option 3 and comment out the options 1 and 2. Wire the graphic display as per the house fan requirements and it should work.

    // Option 3: testing pins used in Whole House Fan Node
    #define TFT_CS     3
    #define TFT_DC     6
    #define TFT_MOSI   7
    #define TFT_SCLK   8
    #define TFT_RST    0  // you can also connect this to the Arduino reset
                          // in which case, set this #define pin to 0
    
    Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
    

    If it does not work the same as when connected to the standard connections , then your wiring is in error and need to be changed to make it work before proceeding to the other sketch.



  • Thank you very much. Star Over. Rewire display and change the code. Never thought I would be excited to see the word ”Error” on display :).
    I got five NRF24L01+. Two of them are not working at all. Looks like the one on the gateway working ok, but the node is unstable.
    Do I need to create an additional device for Fan in Vera or, it will be displayed within the MySensors serial gateway?


  • Admin

    @hard-shovel Thanks for the help.

    @lis610 You are picking a very advanced project to start with. If you have the time I'd suggest an easier project like a motion sensor to get started. If you want to keep going I'd suggest doing some additional reading/watching on how this all works. Not trying to be critical but rather save you frustration.

    I'm not running UI7 on my Vera so I haven't tested but it should automatically create your device as long as you are including it when first starting the node. For me I press the "Start" button then power up my node (the fan in this case).
    0_1531784492388_5544c5b2-5b0e-412e-9abd-411d52e298ef-image.png

    However, if you don't have good communication it may not add correctly.



  • .......Thanks



  • Replaced NRF24L01+ and it is working now.
    Having trouble with DHT22 it is working on MEGA, but not on Pro Mini ATMega328P 3.3V 8MHz any suggestions



  • @lis610 I find that at 3.3 some of my DHT22s are unreliable and at 3.2V it just gets worse..
    The data sheet shows the minimum voltage as being 3.3V, and i suspect my Chinese supplied items are not within specification.
    while you are using a 3.3V pro mini do you have a 5V supply for the DHT22?
    You will find they are much more reliable at the higher voltage.


  • Admin

    @lis610 Great news! I echo what @hard-shovel said. I try to supply my 5v sensors with 5v power from a regulator (with the appropriate capacitors) instead of my Arduino.



  • I am using 5V power supply and testing sensor with DHT example. DHT is working with MEGA power by 3.3 or 5 v. Maybe it is not working because of Pro Mini 8MHz?


  • Admin

    @lis610 It should work at 8MHz. Have you double checked the wiring? Did you try with the default sketch in the DHT library? What are the debug messages saying?



  • @lis610 DHT22 being a "one wire" protocol, are timing dependent. Make sure that you have defined #define F_CPU 8000000L or have selected the 8mhz option in the newer versions of the IDE. If #define F_CPU gives you an error, you have to do it in the IDE.
    Are you using the Adafruit DHT library? Which version? To double check that your CPU frequency is correct, create a new sketch with the following:

    void setup() {
      pinMode(13, OUTPUT);
    }
    
    void loop() {
      digitalWrite(13,HIGH);
      delay(10000);
      digitalWrite(13,LOW);
      delay(10000);
    }
    

    Then time the speed of the blinks. it should be 10 seconds on and 10 seconds off. if you're getting 20 seconds on and 20 seconds off, your F_CPU is wrong.



  • Thank you, guys.
    Got the DHT working! Next step connect motor and fan, fingers crossed 🙂



  • @lis610 you can't just leave us hanging and say "it's working", tell us what the problem was. Was it wiring, was it the 8mhz, was it a wrong library setting, was it a bad sensor? What did you do to make it work? The next person will want to know because they could have the same issue and it teaches the rest of us which troubleshooting tips are working.



  • In the beginning, I connected the DHT sensor to Pro Mini A0 and separate power supply (5V) and ran DHT Example sketch and eading was "nan". Want to mention that all other wires (FAN setup ) attached to Pro Mini as well. Then I disconnect Pro Mini from setup and connect DHT to it (GND, VCC, and A0) got numbers by running DHT Example. Connect everything together (motor, display, radio) and connect DHT to Pro Mini (GND, VCC, and A0) turn on and got zeros for Temp and Hum. Got frustrated and left for a walk. When I come back, Temp: 85 and Hum 52. I was not patient enough. It takes 5 to 6 min for Temp to show on display. I also tried to connect DHT VCC to the external power supply 3.3 and 5 V, but leave GND connected to Pro Mini and it works.



  • Finish! Thank you for all your help!

    0_1533177411968_91c3b0fa-87ff-4514-811c-ffa101bbad98-image.png ![alt text](image url)
    0_1533177453426_38d363a5-596c-4626-82d1-b4e6de2260c7-image.png
    0_1533177489450_910be9d8-b98d-465c-98eb-7bed5d71b63e-image.png


  • Admin

    @lis610 Awesome! Congratulations and great job for not giving up. That was a lot to tackle for a first project! Nice enclosure to house everything. Looks way cleaner than mine 🙂



  • Can you add additional code; Close the cover if Fan does not start and display error that fan has no power. Thank you.



  • Display. I used old case from iPod. Sprayed a little red paint and top it with black. Push button at the bottom of the case.0_1533511027712_IMG_4216.JPG



  • Looks great @lis610 !



  • I am using RCWL-0516 Microwave Radar Sensor for on/off the display. This sensor is very sensitive. I just want to activate the display in a close range. Any suggestions?



  • @lis610 said in 💬 Insulated Whole House Fan:

    RCWL-0516

    https://www.rogerclark.net/investigating-a-rcwl-9196-rcwl-0516-radar-motion-detector-modules/ shows some possible ways to read something other than a digital output of motion at 5 to 7 meters.

    It doesn't look like there is a simple way to just make it less sensitive.



  • @lis610 said in 💬 Insulated Whole House Fan:

    I am using RCWL-0516 Microwave Radar Sensor for on/off the display. This sensor is very sensitive. I just want to activate the display in a close range. Any suggestions?

    You could try the XYC-WB-DC radar sensor. This one allows the sensitivity to be adjusted by changing a resitor value. Here's a Youtube video about it:

    Modifying a XYC-WB-DC Microwave Motion Sensor for use in a Sonoff SC – 19:09
    — Blair Thompson

    I'm waiting for mine to come in from China, so no first hand experience yet on how these sensors work.



  • @lis610 I have found with a 499K resistor the range is reduced to about 1.2m in a ABS box.
    With a 1Mohm it was about 3m, I do not have many high value SMD resistors to experiment with but the lower the value the lower the range.

    0_1533564303458_Img_4277x.jpg

    Just tried with a 333K and it operates about 0.8m in free air.


Log in to reply
 

Suggested Topics

0
Online

11.4k
Users

11.1k
Topics

112.7k
Posts