stefanbode / Sonoff-Tasmota

Provide ESP8266 based itead Sonoff with Web, MQTT and OTA firmware using Arduino IDE, enhanced with I2C options
GNU General Public License v3.0
127 stars 41 forks source link

Q: How do you control your "sensor's power pin" and how to add simple analog multiplexer? #159

Closed curlyel closed 4 years ago

curlyel commented 5 years ago

Hi Stefan, thanks a lot for your Tasmota fork! I really like the extended deepsleep stuff and the counter devider. Actually, I designed a ESP8266 sensor pcb just around "your" Tasmota, while having lowest power consumption with deepsleep etc. in mind ;-)

Before making my hands dirty on modifying the source myself, I have two questions ;-):

How do you control external sensor power? To cut the standby power consumption of external sensors, I've put a MOSFET high-side switch on the board controlled by a GPIO, quite similar to what you wrote in the wiki:

I use one GPIO to trigger a BC337 transistor to switch OFF all of my connected devices during deepsleep.

Q: How do you control the corresponding pin? Just configured as a relay and switched on/off by a rule?

How to control a ADC "multiplexer"? I need to measure some external voltage. Sure, this done by the Analog0 reading. BUT: Since the sensors are powered by battery, I'd like to monitor the battery voltage too. Using e.g. i2c ADS1115 is to much overhead here, so I decided to solder a simple two-input analog switch ic on the board. This - again - is controlled by a GPIO:

low=external voltage is switched to the A0 pin (even in deep sleep due to a pull-down resistor)
high=battery voltage is switched to the A0

As a side-effect, this "cuts" the voltage divider on the battery line during deepsleep (leak current = 0 ). This gives me two possible analog readings... (Analog0 and Analog1)

Q: Where to add the corresponding code to? Mainly to xsns_93_voltage.ino quite likely. But how to register the additional value Analog1 to get published to MQTT and shown in the Web-If?

Would really appreciate some advise to start in the right direction ;-)

stefanbode commented 5 years ago

Hi, please take a look in the wiki at deepsleep about the default power level of the different GPIO during deepsleep. Some of them goto zero by default. This is very convenient to cut off the power with a mosfet or a simple transistor. Works also very well. Define on the GPIO a relay and switch it to ON. On every reboot the device resume the last state and switches on your devices. Bang!
This also works with i2c based adc multiplexers. I also have one and it works like a charm. The power ON will come very fast after restart. Less than a second. The deepsleep roughly 10seconds later. This is far more time than any device needs to initiate. The ads1115 is really a good choice. If you need some interaction to get the different values you’re in trouble. You get a board at AliExpress for only a few bucks and it really pays of with a much more simple implementation.

curlyel commented 5 years ago

Hi Stefan, thanks a lot for your guidance!

ads1115 is really a good choice

Yes indeed. I've considered it too when designing the PCB. But the versions on breakout boards seemed to me beeing a bit chunky to fit into the desired enclosure (along the other PCB and the battery) and the bare ADS1115 is 0.5mm pin pitch which is a bit hard for me for hand-soldering ;-)

Aside from that: I made the decision one day to use the analog switch to "double" the ADC channels and made the PCB's with the design for it. So I have to live with it ;-)

So I've made some modifications on the source code to support "my" new GPIO types:

//CUR mod
  GPIO_PWR_SENSOR,     // GPIO to switch external sensor's power on
  GPIO_ADC_MUX,        // GPIO to select A0 input 
//end
  GPIO_SENSOR_END };

So you can select them from the UI now:

GPIO-Types-mini

And the two analog values are shown in the UI as well as in the tele-JSON:

WEB-UI-mini

09:26:18 RSL: tele/sonoff/SENSOR = {"Time":"2019-07-19T09:26:18","ANALOG":{"A0":5,"A1":898}}

I've started to do similar modifications for the "Sensor-Power-GPIO" so that sensors will actively switched off before deepsleep and switched on after full wakeup. Means, it does not depend on some relay setting anymore if selected the according GPIO for it.

If you like, I can issue a pull request later for it when I have done more testing. I think, at least the sensor-power stuff could be interesting for others as well ;-)

Have to admit, the analog-switch thing is somehow specific and just helpful if somebody is building its own circuitry around the ESP8266. But who knows ...

stefanbode commented 5 years ago

Hm, Tjark Auto power off of defined gpio before deepsleep and power in is a quite good idea. Iwould do it by using the setting that all relays start on ON mode and power all down before deepsleep. Thins might be the smallest change to the code. Let me see what your idea is.

curlyel commented 5 years ago

smallest change to the code

I did it that way, that I initialize the GPIO_PWR_SENSOR pin being HIGH at startup if it's been configured by the user:

sonoff.ino:

void GpioInit(void)
{
...
  //CUR mod
  if (pin[GPIO_PWR_SENSOR] < 99) {
    pinMode(pin[GPIO_PWR_SENSOR], OUTPUT);
    digitalWrite(pin[GPIO_PWR_SENSOR], 1);
  }
  if (pin[GPIO_ADC_MUX] < 99) {
    pinMode(pin[GPIO_ADC_MUX], OUTPUT);
    digitalWrite(pin[GPIO_ADC_MUX], 0);
  }
  //end
...
}

Right before the device is falling to sleep, GPIO_PWR_SENSOR is actively set to LOW...

sonoff.ino:

void PerformEverySecond(void)
{
        ...
        RtcSettings.uptime = 0;
        RtcSettingsSave();
        //CUR mod
        if (pin[GPIO_PWR_SENSOR] < 99) {
          digitalWrite(pin[GPIO_PWR_SENSOR], 0);
        }
        //end
        // 10% of deepsleep to retry
        if (MAX_DEEPSLEEP_CYCLE < Settings.deepsleep) {
          ESP.deepSleep(1000000 * (uint32_t)MAX_DEEPSLEEP_CYCLE, WAKE_RF_DEFAULT);
        } else {
          ESP.deepSleep(1000000 * Settings.deepsleep, WAKE_RF_DEFAULT);
        }
        yield();
        ...
}

That's all for the GPIO_PWR_SENSOR handling - beside the definitions in the _sonofftemplate.h mentioned above...

Intentionally I omitted the GPIO_PWR_SENSOR setting before your deepsleep in the setup() procedure since the potential deepsleep call is before GpioInit(). If the device is going to enter another deepsleep cycle, then the GPIO_PWR_SENSOR remains untouched anyway and the pin has to keep the same state as in deepsleep...

Both modifications (GPIO_PWR_SENSOR and GPIO_ADC_MUX) are working so far (will do some more test though ;-) )

stefanbode commented 4 years ago

You can now use rules to power down devices before deepsleep or after wakeup. This should solve your issue. An additional pin I want to avoid and stay more with the standard

stefanbode commented 4 years ago

There will be a new commit today optimize deepsleep in general. Added some checks and optimize runtime. The rules is already committed.

stefanbode commented 4 years ago

Please use a rule on System#Save to switch off your device. To Switch it on on reboot just another rule on System#Boot