SCD30 set the intervals
# help
s
Hi every one, Is it possible to set the measuring interval for scd30? currently it seems that is in the highest measuring interval that causes a lot of energy usage . Thanks in davance
f
I would need to look at the specs for the scd30.
Looking at the code it seems like it's requesting a measurement every time one calls
read
.
The constructor of the driver states that the sensor is initialized in "continuous measurement mode".
But that this can be switched off.
s
yes, true. but in Toit as i checked scd30 toit's driver i found it i snot possible
esp_err_t scd30_get_measurement_interval(i2c_dev_t *dev, uint16_t *interval_seconds) Get measurement interval. Gets the interval used bythe SCD30 sensor to measure in continuous measurement mode. Saved in non-volatile memory.
f
I see.
There is a command (0x4600) that can set the measurement interval in seconds.
it's set to 2 by default (the fastest).
s
can I change it and use my modified librray?
f
Looking into whether there is an easy way to try a higher rate without modifying the package.
(mainly for testing).
Try to add the following after you created the driver. So, let's assume you have
sensor := scd30.Scd30 device
. Then you might be able to change the measuring interval as follows
Copy code
seconds := #[0x00, 0x10]
command := #[0x46, 0x00] + seconds + #[sensor.compute_crc8_ seconds]
sensor.device_.write command
That's reaching into the sensor's private functions, but for testing that should be fine.
If that works I can try to add the missing function(s).
(In the example code here the
seconds
is initialized to 0x10 which is 16. So not a huge difference, but you can increase that to 0xFF (255), or even up to a total of 1800 in which case you also need to change the most-significant byte).
s
basic question. I did not understand where should I add these lines? in my toit program or scd30 toit driver
f
In your toit program.
There should be a place where you create the
Scd30
object.
It should look something like
sensor := scd30.Scd30 device
.
In the example of the package it would be here: https://github.com/jacobqvist/scd30/blob/main/examples/room.toit#L28
s
this is my program. I will add this now
f
In the example the variable is called
scd30
, so just replace my
sensor
with
scd30
.
s
bus := i2c.Bus --sda=gpio.Pin 21 --scl=gpio.Pin 22 device := bus.device Scd30.I2C_ADDRESS scd30 := Scd30 device sleep --ms=5000 while true: reading := scd30.read if reading.co2 > 2000: print "Open your window: $(reading.co2.to_int)ppm" else: print "CO2 level is healthy: $(reading.co2.to_int)ppm" print "Temperature: $(%.1f reading.temperature)ºC" print "Humidity: $(%.1f reading.humidity)%" temperature := reading.co2.to_int client.publish topic_1 "$temperature".to_byte_array sleep --ms=5_500 // temperature := 25 client.publish topic_2 "$temperature".to_byte_array print "i am at deep sleep %" sleep --ms=5_500 esp32.deep_sleep (Duration --s=120) print "I am awake"
here you mean, instead of seconds := #[0x00, 0x10] I have to write seconds := #[0x00, 0xFF]
f
correct.
that would change the interval to 255 seconds.
s
I will back with new results in short time
f
Since I see your code here: Try to call
device.close
and
bus.close
just before the
esp32.deep_sleep
. (You mentioned that the i2c was draining battery. Calling
close
might solve this.)
Another tip: instead of having the
sleep --ms=5_500
you could look at a pin and only go to deep-sleep if that pin is not grounded. Something like:
Copy code
run_jaguar_pin := gpio.Pin 32 --input --pull_up
  if run_jaguar_pin == 0:
    // The pin is pulled to ground.
    // Don't call deep sleep.
    exit 0
You can then install your program with
Copy code
jag container install -D jag.disabled -D jag.timeout=2m scd30 scd30_program.toit
This makes it such that Jaguar isn't even trying to connect to WiFi if your program is running. However, if you program terminates (and doesn't go to deep-sleep) Jaguar starts and you can update the program. You then only need to pull pin 32 to ground (either with a button or with a wire) to start Jaguar.
s
I get this "Received a Toit system message. Executing the command below will make it human readable: ---- jag decode WyNVBVVYU1UPdjIuMC4wLWFscGhhLjc5U1UAWyRVI1UQry2V/nwcXOmPwlKUFjqXWFsjVQRVRVNVCUVYQ0VQVElPTlNVHERldmljZSBpcyBub3QgZ2V0dGluZyByZWFkeS5bI1UCVVNbI1UKWyNsAAAAA1VGVQBJKs9bI2wAAAADVUZVAUkrGVsjbAAAAANVRlUCSQJKWyNsAAAAA1VGVQNJB4FbI2wAAAADVUZVBEkJLVsjbAAAAANVRlUFSQlEWyNsAAAAA1VGVQZJCPJbI2wAAAADVUZVB0kye1sjbAAAAANVRlUISTKQWyNsAAAAA1VGVQlJB54="
f
When did you get this error?
I'm also surprised that Jaguar can't decode the message. If you run a program with
jag run
it should store the snapshot with debug information in your cache directory.
s
nad my SCD30 is not working any more
when I add these line to increase the interval
f
You then execute it with
jag run
?
s
no
f
jag container install
?
s
jag container install ..
f
and there is no stack trace?
and running
jag decode WyN...
does not work?
s
I did not try this
f
Normally
jag monitor
should do it for you.
s
i copied from jag monitor
f
I don't understand why you wouldn't get a stack trace.
I would still run the command.
It gives a bit more information on why it can't decode it.
s
I did this, there was a problem in my code. Now I solved
Thanks a lot. now there is no energy leakage from SCD30.
I am really appreciated for your support
f
I would need to read a bit more the datasheet, but note that increasing the measurement interval means that reading the measurement might be quite out of date.
It could be better to stop continuous measurement before you go to deep-sleep and to start the sensor up when you need new measurements.
s
yes, I agree. because I get this error some times: EXCEPTION error. Device is not getting ready. 0: Scd30.wait_for_ready_ /driver.toit:58:20 1: Scd30.read /driver.toit:108:5 2: main adafruit_1.toit:74:22
f
I think that's because the device uses clock stretching which only works up to a certain point on the esp32.
Not 100% sure, but it would explain it.
That said. It it might just be that the
wait_for_ready_
isn't waiting long enough.
It's currently waiting 2 seconds in total.
s
But before I have added those lines, I never face with error. But now, every time the toit container wakes up from deep sleep mode I face this error
f
nevermind.
I understand now.
When you set the sensor to continuous measurements the sensor is automatically updating a measurement every x seconds.
It stores the read value in its own memory.
When it has a value it responds to 'is-data-ready?' with 1.
If the measurement isn't there yet, it returns with 0.
Once you read a value, the
is-data-ready
switches back to 0.
That is, using the Toit driver here, you can only read the latest measurement once, as the driver checks that a measurement is ready.
By switching to a higher measurement interval you instructed the sensor to sample only every 255 seconds (or ever less often).
Once you have read the measurement the sensor marks the data as read and will respond 'is-data-ready?' with "0".
So if you ask the sensor for a measurement more often than every 255 seconds you will now get this error message.
If you only want to save power, wouldn't stopping continuous mode be more what you want?
Tell the sensor to stop sampling while you don't need it.
s
ok. I fully understand what you said. but i think it might be sth else. because when I also put 0x00, 0x10 and every 120 seconds repeat it, I also get that error
f
Then, when you want to measure you start continuous mode again.
s
excatly
f
ok. That's weird.
s
How can i tell the sensor to stop continuous measurement
f
scd30.continuous_mode = false
Be aware that turning on the continuous mode takes a few seconds.
So you might need to add a
sleep --ms=5_000
or so before you can read the new measurement.
s
Class 'Scd30' does not have any method 'continous_mode'
f
sorry. typo. I updated my response.
s
I am writing like this: device := bus.device Scd30.I2C_ADDRESS scd30 := Scd30 device scd30.continuous_mode = false
f
correct.
So actually, what you probably want is: set it to true when you start up.
s
I will update you in 2 mins
f
then set it to false before you go to deep-sleep.
s
ok
f
I looked through the datasheet. Couldn't see any data on how long it takes for the first measurement.
However, since it can measure every 2 seconds, I would hope that it doesn't take longer than that.
In that case you shouldn't need any
sleep
.
Btw. Here is the datasheet.
It needs a minute before it gives a good measurement?
s
I am not sure. I just saw it in a paper
f
In that case you should consider the following approach: - set the sensor to continuous mode (2s would be fine). - go to deep-sleep for a minute (or two). - read a new measurement. - disable continuous mode - go to deep-sleep for much longer (like an hour or so).
You can use
import system.storage
to store a bit of information in RTC memory which survives deep sleep. So you could store there whether you want to enable continuous mode, or whether you want to read a measurement.
s
when I follow this steps I get agian the same error :Class 'Null_' does not have any method 'write_'. 0: Device.write /i2c.toit:168:10 1: Device.write /i2c.toit:161:5 2: Scd30.continuous_mode= /driver.toit:94:15 3: main adafruit_1.toit:92:27
f
did you do this before you called
device.close
?
s
oh, no
f
Also note: the interval is written into the sensor. So you might want to reset it to 2 seconds if changing the continuous mode is what you want.
s
Now, I put it before device.close but still error : Class 'Null_' does not have any method 'write_'. 0: Device.write /i2c.toit:168:10 1: Device.write /i2c.toit:161:5 2: Scd30.continuous_mode= /driver.toit:94:15 3: main
f
can you show me your program again?
(use triple back-ticks to preserve indentation)
s
Copy code
ADAFRUIT_IO_FEEDNAME_1 ::= "Humidity New"
ADAFRUIT_IO_FEEDNAME_2 ::= "Co2"



HOST ::= "io.adafruit.com"
co2_level := 0.0
main:
  network := net.open
  print "I am trying to connect"
  transport := mqtt.TcpTransport.tls network --host=HOST
      --root_certificates=[ certificate_roots.DIGICERT_GLOBAL_ROOT_CA ]
  /**
  // Alternatively, you can also connect without TLS, by using the
  // following transport:
  transport := mqtt.TcpTransport network --host=HOST
  // In that case you can remove the `certificate_roots` import.
  */

  client := mqtt.Client --transport=transport

  options := mqtt.SessionOptions
    --client_id = "toit-example-client"
    --username = ADAFRUIT_IO_USERNAME
    --password = ADAFRUIT_IO_KEY

  client.start --options=options

  print "Connected to broker"

  topic_1 := "$ADAFRUIT_IO_USERNAME/feeds/$ADAFRUIT_IO_FEEDNAME_2"
  topic_2 := "$ADAFRUIT_IO_USERNAME/feeds/$ADAFRUIT_IO_FEEDNAME_1"

  bus := i2c.Bus
    --sda=gpio.Pin 21
    --scl=gpio.Pin 22

  device := bus.device Scd30.I2C_ADDRESS
  scd30 := Scd30 device
  scd30.continuous_mode = true 
  sleep --ms=5000

  //seconds := #[0x00, 0x10]
  //command := #[0x46, 0x00] + seconds + #[scd30.compute_crc8_ seconds]
  //scd30.device_.write command

  while true:
    reading := scd30.read
    if reading.co2 > 2000:
      print "Open your window:     $(reading.co2.to_int)ppm"
    else:
      print "CO2 level is healthy: $(reading.co2.to_int)ppm"
      print "Temperature:          $(%.1f reading.temperature)ºC"
      print "Humidity:             $(%.1f reading.humidity)%"
    temperature := reading.co2.to_int
    client.publish topic_1 "$temperature".to_byte_array
    sleep --ms=5_500
   // temperature := 25
    client.publish topic_2 "$temperature".to_byte_array
    print "i am going to deep sleep %"
    sleep --ms=5_500
    scd30.continuous_mode = false 
    device.close  
    bus.close
    esp32.deep_sleep (Duration --s=90)
    print "I am awake"



  client.close
f
Please put triple back-ticks around your code.
back-ticks not ticks.
(but I can read enough).
I can't see how this program can have the error you showed.
the device is clearly open and there is no reason the call to i2c write would fail.
Can you send me the full stack-trace. (including the line of main)
Also: I would move the
sleep --ms=5_500
to just before the
esp32.deep_sleep
call. This way you already turn off the device/bus 5 seconds earlier.
s
jag decode WyNVBVVYU1UPdjIuMC4wLWFscGhhLjc5U1UAWyRVI1UQCnNMZGzvVV+0mPI//HU6flsjVQRVRVNVDUxPT0tVUF9GQUlMRURbI2wAAAADVUFVA1sjVQNJBnpVX1pbI1UCVVNbI1ULWyNsAAAAA1VGVQBsAAD0ZVsjbAAAAANVRlUBbAAA9FFbI2wAAAADVUZVAmwAAIFMWyNsAAAAA1VGVQNJBXdbI2wAAAADVUZVBEkLmVsjbAAAAANVRlUFSQ1FWyNsAAAAA1VGVQZJDVxbI2wAAAADVUZVB0kNClsjbAAAAANVRlUIbAAArL9bI2wAAAADVUZVCWwAAKzUWyNsAAAAA1VGVQpJC7Y= Class 'Null_' does not have any method 'write_'. 0: Device.write /i2c.toit:168:10 1: Device.write /i2c.toit:161:5 2: Scd30.continuous_mode= /driver.toit:94:15 3: main adafruit_1.toit:92:27
f
That's still the same line number (92) as before.
Are you sure it is executing the modified program?
s
yes
line 92 is bus.close
maybe there is a conflict between bus.close and stop continuously measurment
f
No.
The stacktrace clearly states that it's going through
Scd30.continuous_mode=
.
I would try to reinstall the container again.
s
ok
DEBUG: Connected to broker DEBUG: Connection established Connected to broker ---- Received a Toit system message. Executing the command below will make it human readable: ---- jag decode WyNVBVVYU1UPdjIuMC4wLWFscGhhLjc5U1UAWyRVI1UQqc9PDXgdWXmZcw297YaQf1sjVQRVRVNVCUVYQ0VQVElPTlNVEEkyQ19XUklURV9GQUlMRURbI1UCVVNbI1UOWyNsAAAAA1VGVQBsAAD0OlsjbAAAAANVRlUBbAAA9TVbI2wAAAADVUZVAmwAAPRlWyNsAAAAA1VGVQNsAAD0UVsjbAAAAANVRlUEbAAAgXlbI2wAAAADVUZVBWwAAIE8WyNsAAAAA1VGVQZJBMVbI2wAAAADVUZVB0kLmVsjbAAAAANVRlUISQ1FWyNsAAAAA1VGVQlJDVxbI2wAAAADVUZVCkkNClsjbAAAAANVRlULbAAArL9bI2wAAAADVUZVDGwAAKzUWyNsAAAAA1VGVQ1JC7Y=
EXCEPTION error. I2C_WRITE_FAILED 0: Device.write. /i2c.toit:161:18 1: Bus.write_ /i2c.toit:90:18 2: Device.write /i2c.toit:168:10 3: Device.write /i2c.toit:161:5 4: Scd30.set_pressure_ /driver.toit:101:13 5: Scd30.continuous_mode= /driver.toit:92:7 6: main adafruit_1.toit:68:25
after reinstall the container
f
ok. That's a different error.
Move the
continuous_mode = true
line to after the
sleep
.
s
ok
ok, it has been solved and also no further energy wastage by continues measurements ,
f
great.
I'm spending a few minutes on improving your code.
Will send it to you when I'm done.
s
I am deeply grateful
f
In the meantime: I would decomment the following lines and reset the interval to 2 seconds:
Copy code
seconds := #[0x00, 0x02]
  command := #[0x46, 0x00] + seconds + #[scd30.compute_crc8_ seconds]
  scd30.device_.write command
You only need to run it once. The sensor will save it in its own memory.
s
ok, thanks. but I do not why I face this error again: jag decode WyNVBVVYU1UPdjIuMC4wLWFscGhhLjc5U1UAWyRVI1UQlFb87NpBUi2mjKYrpKY7k1sjVQRVRVNVCUVYQ0VQVElPTlNVHERldmljZSBpcyBub3QgZ2V0dGluZyByZWFkeS5bI1UCVVNbI1UKWyNsAAAAA1VGVQBsAACBFFsjbAAAAANVRlUBbAAAgYRbI2wAAAADVUZVAkkE0VsjbAAAAANVRlUDSQuZWyNsAAAAA1VGVQRJDUVbI2wAAAADVUZVBUkNXFsjbAAAAANVRlUGSQ0KWyNsAAAAA1VGVQdsAACsv1sjbAAAAANVRlUIbAAArNRbI2wAAAADVUZVCUkLtg== EXCEPTION error. Device is not getting ready. 0: Scd30.wait_for_ready_ /driver.toit:58:20 1: Scd30.read /driver.toit:108:5 2: main adafruit_1.toit:77:22
f
after setting the interval to 2s?
or in general?
s
no, i did not check with interval 2 s yet. a moment please
yes. it happens again: jag decode WyNVBVVYU1UPdjIuMC4wLWFscGhhLjc5U1UAWyRVI1UQpcS+BbwIW4uSqlz4bHR+S1sjVQRVRVNVCUVYQ0VQVElPTlNVEEkyQ19XUklURV9GQUlMRURbI1UCVVNbI1UMWyNsAAAAA1VGVQBsAAD0WVsjbAAAAANVRlUBbAAA9VRbI2wAAAADVUZVAmwAAPSEWyNsAAAAA1VGVQNsAAD0cFsjbAAAAANVRlUESQTdWyNsAAAAA1VGVQVJC7hbI2wAAAADVUZVBkkNZFsjbAAAAANVRlUHSQ17WyNsAAAAA1VGVQhJDSlbI2wAAAADVUZVCWwAAKzeWyNsAAAAA1VGVQpsAACs81sjbAAAAANVRlULSQvV EXCEPTION error. I2C_WRITE_FAILED 0: Device.write. /i2c.toit:161:18 1: Bus.write_ /i2c.toit:90:18 2: Device.write /i2c.toit:168:10 3: Device.write /i2c.toit:161:5 4: main adafruit_1.toit:70:17
but different error
Copy code
`
device := bus.device Scd30.I2C_ADDRESS
  scd30 := Scd30 device
  seconds := #[0x00, 0x02]
  command := #[0x46, 0x00] + seconds + #[scd30.compute_crc8_ seconds]
  scd30.device_.write command
  sleep --ms=5000
  scd30.continuous_mode = true
f
Is line 70 the one with
scd30.device_.write command
?
I see.
Move the
sleep --ms=5000
directly after the
scd30 := Scd30 device
.
s
ok
Untested, but I hope it will work.
You don't need to use everything I put in there, but this is relatively close to what I would have done.
s
I will test it now
f
There are a few things that would influence the program: - does the sensor really need some time before it provides good measurement? - how often do you want to measure? - do you want to send data immediately, or do you want to save some in flash before you send it to the mqtt server. All of these influence the design and the power consumption.
Did you succeed in changing the interval back to 2s ?
s
great. thanks a lot. I will consider them
yes. and till now it is working without problem 🙂
f
great.
You can remove that code now.
(If you haven't done so yet).
s
interesting. so now it is set
f
yes.
the sensor remembers the interval.
s
Thanks a lot, the program works seamlessly without any problem
I am incredibly grateful for your support
f
Great. If you haven't done so yet: try to understand everything.
there are things in there that should be tweaked.
And some things might be overkill for you.
so don't feel obligated to take everything.
s
ok, sure.