How to query GPIO states?


#1

I am planning to use the Ruuvitag to monitor the status of my windows/doors. So I plan to connect a door contact to a GPIO. Or in case where there are two windows connect even two of them.

I plan on using normally open reed relays so they will be in closed state when the window is closed.

I have a few question on how to implement this:

  • Does it make a difference which GPIOs I use? My current criteria is: where is it easiest to solder a wire to it :slight_smile: https://lab.ruuvi.com/pinout/
  • Do I need to add a pull-up resistor to the GPIO or do they have internal pull-up/pull-down resistors?
  • If there are internal resistors: can I configure them for a GPIO? How?
  • How do I query the state of a GPIO from Espruino? Do I need to add any libraries?

42


#2

PuckJS GPIO functions should work as-is, nRF52 has internal pull-up and pull-down resistors. Button examples should get you started.


#3

Thanks a lot. This helped greatly. It is really very easy to do and I got it to work almost immediately.

I now soldered two wires, one to GPIO 18 and the other to plus. Then I connected some door contacts (reed relay) to the wires. The prototype is so far working fine. The plan is to have one Ruuvitag with door/window contact per room to monitor it.

This is the code I used to read and transmit the status from the Ruuvitag:

pinMode(18, 'input_pulldown');

    setWatch(function(e) {
      console.log("Window closed");
      var door = 1;
      NRF.setAdvertising({
        0x2a3f : [door]
          });
    }, 18, { repeat: true,debounce:50, edge: 'rising' });

    setWatch(function(e) {
      console.log("Window open");
      var door = 0;
      NRF.setAdvertising({
        0x2a3f : [door]
          });
    }, 18, { repeat: true,debounce:50, edge: 'falling' });

To send the door status to also required some changes on EspruinoHub. This relates to my other post which I will update separately.

I have one question though. I hope someone can answer this: the reed-relay that I am using is closed when the window is closed. This will be the normal, much more common status. What does this mean for the battery life compared to having the contact open when the window is closed? Would it be better to change this?

42


#4

If you have pull-up activated and constantly leaking through closed reed relay, you’ll consume a lot of power. I think nRF52 GPIO pull-ups are in range of ~10 k ohms, so you might lose hundreds of microamperes through pull-up. That can be 10x as much as the entire consumption of tag otherwise.

It would be better to change to normally open relay.


#5

Thanks. Now I am starting to wonder if it is such a good idea to modify the Ruuvitag as I planned. After changing the reed relay so that it is open when the window is closed I will still have the problem that in summer times the window might be open for a really long time. How can I keep the power consumption to a minimum?

  • Would it be worthwhile not to use the internal resistors and use an external pull-down resistor? If so, how large?
  • May be to use a circuit that only triggers a a short pin level change when the reed relay is changing its status? Any suggestion?

Any other suggestion?

42


#6

You could sample the sensor every few seconds, i.e. pull-up, wait a few µs for reading to stabilise, and then deactivate the pull-up.


#7

This is obviously the easiest to do :slight_smile: , especially since I will use this only to monitor if windows are open. I do not intend to use this as a burglar alarm.

A question here: is "pinMode (18,‘analog’) " the right way to deactivate the pull-down resistor or is there a better way?

I now changed the door/window monitoring code to this but the code is behaving strange. If I deactivate the setTimeout (as done in the code below) then the code works. It seems that I do not need an extra delay after setting the pinMode. I planned, just to be safe, to use the code below with tthe setTimeout-function enabled but I have realized a problem with setTimeout.The second interval to report humidity, battery and pressure is called only after every 10-15 times for the other interval. Not every 2nd time as it should. If the interval for humidity, battery and pressure is larger than the one for temperature and door then it seems to work correct. Any idea why?

42

var Ruuvitag = require("Ruuvitag");
Ruuvitag.setEnvOn(true); 

    setInterval(function(){
        pinMode(18, 'input_pulldown');
//		setTimeout(function(){
			var door = digitalRead(18);
			var temperature = [Math.round(Ruuvitag.getEnvData().temp*100)/100];
			console.log("Door = " + door);
			console.log("Temperature: " + temperature);
			  
			  NRF.setAdvertising({
				0x2a3f : [door],
				0x1809 : [encodeFloat100(temperature)],
			  });
//        },50);
        pinMode(18, 'analog');

   }, 2000);

    setInterval(function(){

    var pressure = [Math.round(Ruuvitag.getEnvData().pressure*10)/10];
    var humid = [Math.round(Ruuvitag.getEnvData().humidity*10)/10];
	var battery = [Math.round(NRF.getBattery()*100)/100];
	console.log("Battery [V]: " + battery);

    console.log("Pressure: " + pressure);
    console.log("Humidity: " + humid);

      NRF.setAdvertising({
		0x2A6D : [encodeFloat10(pressure)],
		0x2A6F : [encodeFloat10(humid)],
		0xfffe : [encodeFloat100(battery)]
      });
            },4000);

 

    function encodeFloat10(num) {
      var d = Math.round(num*10);
      return [ d&255, d >> 8 ];
    }

    function encodeFloat100(num) {
      var d = Math.round(num*100);
      return [ d&255, d >> 8 ];
}

#8

I would use "pinmode(18, ‘input’) to deactivate the resistor, analog input might work just as well but on the other hand it might activate some of the analog circuitry.

I think one problem with your timeout is that you deactivate the pulldown before timeout occurs. I would move the second pinMode call inside timeout.

I’m not sure why environmental readings would be called less frequently than expected. intervals on reads look fine to me :thinking:


#9

look here:
https://www.espruino.com/Reference#l__global_pinMode


#10

@Frida854
Thanks. Though this does not tell which setting is better for disabling the pull-down resistor. I read somewhere that setting it to analog will use less power but I cannot find this anymore and I am not 100% it was for this chip. So I am using now the setting ‘input’.


#11

@otso
the line for deactivating was really in the wrong place. This happened when I moved things around for testing. Most of the times it was inside the loop. I used now the code below for testing.

I now ran a serious of tests with the code below using different intervall settings and timeout settings. Conclusion is:

  • When setTimeout is not used the code behaves as expected
  • When setInterval is larger for interval 2 than for interval 1 the code behaves as expected
  • When setInterval is larger for interval1 than for interval 2 then the code does not behave as expected and prints the data in interval 2 to the console only every X times it prints it for data in interval 1. X depends on the value for setTimeout. The longer the timeout the more “normal” the code behaves.

I am using the code now without setTimeout. I would like to know why the code behaves as it does but I think I just let it rest now.

var Ruuvitag = require("Ruuvitag");
Ruuvitag.setEnvOn(true); 

    setInterval(function(){
        pinMode(18, 'input_pulldown');
//		setTimeout(function(){
          var door = digitalRead(18);
          var temperature = [Math.round(Ruuvitag.getEnvData().temp*100)/100];
          console.log("Door = " + door);
          console.log("Temperature: " + temperature);
          NRF.setAdvertising({
            0x2a3f : [door],
            0x1809 : [encodeFloat100(temperature)],
          });
        pinMode(18, 'input');
        //},10);
   }, 20000);

    setInterval(function(){
      var pressure = [Math.round(Ruuvitag.getEnvData().pressure*10)/10];
      var humid = [Math.round(Ruuvitag.getEnvData().humidity*10)/10];
      var battery = [Math.round(NRF.getBattery()*100)/100];
      console.log("Battery [V]: " + battery);

      console.log("Pressure: " + pressure);
      console.log("Humidity: " + humid);

        NRF.setAdvertising({
          0x2A6D : [encodeFloat10(pressure)],
          0x2A6F : [encodeFloat10(humid)],
          0xfffe : [encodeFloat100(battery)]
        });
     },60000);

    function encodeFloat10(num) {
      var d = Math.round(num*10);
      return [ d&255, d >> 8 ];
    }

    function encodeFloat100(num) {
      var d = Math.round(num*100);
      return [ d&255, d >> 8 ];
}

Test results:

Test 1
setInterval 1: 2000ms setTimeout: 10ms
setInterval 2: 4000ms

approx. every 27 times (varies slightly) when when console.log is done for interval 1 it is also shown for interval 2

Test 2
setInterval 1: 2000ms setTimeout: 50ms
setInterval 2: 4000ms

approx. every 17 times when when console.log is done for interval 1 it is also shown for interval 2

Test 3
setInterval 1: 2000ms setTimeout: 500ms
setInterval 2: 4000ms

Every 5 times when when console.log is done for interval 1 it is also shown for interval 2

Test 4
setInterval 1: 2000ms setTimeout: 1000ms
setInterval 2: 4000ms

Every 3 times when when console.log is done for interval 1 it is also shown for interval 2

Test 5
setInterval 1: 4000ms setTimeout: 10ms
setInterval 2: 2000ms

Every second time console.log is done for interval 2 it also is shown for interval 1 (data of both console log data slightly mixed)

Test 6
setInterval 1: 2000ms no setTimeout used/disabled in the code below
setInterval 2: 4000ms

Every 2nd time console log is done for interval 1 it is also done for interval 2.