openenergymonitor / emonhub

Python service linking and decoding input to MQTT & Emoncms
90 stars 83 forks source link

SDS011 dust sensor implementation update #139

Closed danbates2 closed 4 years ago

danbates2 commented 4 years ago

This uses a much improved library to manage the SDS011 dust sensor. It enables the rate at which the sensor is read to be changed to assist in the internal laser lasting longer. As we know, the laser, running 24/7, will reach it's rated life in less than a year. Setting readinterval to 5 will give a dust sensor reading ever 5 minutes, elongating the life of the sensor to something more like 5 years.

Below is required to install the python library.

$ sudo pip3 install sds011

danbates2 commented 4 years ago

tested, ready to merge. @TrystanLea @glynhudson

TrystanLea commented 4 years ago

Thanks @danbates2 this is great!

Unfortunately Im having trouble with the blocking nature of the read function, when you try and restart or stop emonhub it just hangs there until its finished the latest set of readings. I've had a go at trying to call del from a signal or trigger from the main emonhub thread but no luck so far.

I've also made some other minor modifications here https://github.com/openenergymonitor/emonhub/commits/sds011

TrystanLea commented 4 years ago

I tired adding adding the following to emonhub.py in the close section to then call a close method in the interfacer

def close(self):
    """Close hub. Do some cleanup before leaving."""

    self._log.info("Exiting hub...")

    for I in self._interfacers.values():
       close = getattr(I, "close", None)
       if callable(close):
           I.close()

    for I in self._interfacers.values():
        I.stop = True
        I.join()

and then in the SDS011 interfacer:

def close(self):
    self._log.info("Closing SDS011")
    # self.sds.ser = False
    sds.__del__()

But no luck, need to somehow get the message that emonhub needs to close/restart into the SDS011 library thread...

TrystanLea commented 4 years ago

Perhaps using this library might be easier? https://github.com/ikalchev/py-sds011

TrystanLea commented 4 years ago

Hmm not sure that Im getting that library to work ... might be that the sds011 has the settings from the previous library and there's some conflict between active and passive mode not sure..

danbates2 commented 4 years ago

@TrystanLea

Unfortunately Im having trouble with the blocking nature of the read function

Right, I see what you mean with the emonhub restarts.

That other library could be the solution in that case.. (that other library gives us easier control of sleep times and readings too..)

I guess another way would be to put the process into a thread.

I also don't know the procedure for emonhub stopping interfacers. Is there a function it calls to stop interfacers?

TrystanLea commented 4 years ago

I also don't know the procedure for emonhub stopping interfacers. Is there a function it calls to stop interfacers?

Yes and I tried tried to get that to work above, see 3rd comment back, but no luck in affecting the underlying thread unfortunately..

danbates2 commented 4 years ago

Sure. Who knows emonhub better? What's the procedure for closing interfacers?

TrystanLea commented 4 years ago

That wasnt the issue, the close command was getting through to the interfacer, it was just that it wasnt getting into the sds011 library thread to close it as it where..

danbates2 commented 4 years ago

When stopping emonhub, the interfacers get stopped too. Is this always by this?..

def close(self):
danbates2 commented 4 years ago

Because one option is to put the serial stuff into a thread, and stop the thread when closing the interfacer.

TrystanLea commented 4 years ago

The interfacers have a run method with a while loop, this loop exists if the stop flag is set to true: https://github.com/openenergymonitor/emonhub/blob/new_config_format/src/emonhub_interfacer.py#L94

the stop flag is set from emonhub.py when the users attempts to stop/restart emonhub here: https://github.com/openenergymonitor/emonhub/blob/new_config_format/src/emonhub.py#L148

the run method calls the read method that you see in the SDS011 interfacer: https://github.com/openenergymonitor/emonhub/blob/new_config_format/src/emonhub_interfacer.py#L99

danbates2 commented 4 years ago

Cool. But what about calling

def close(self):

? I can't see that anywhere.

danbates2 commented 4 years ago

I can see the stops in the main emonhub, but I can't see how each interfacer is actually closed. I think emonhub just waits for a read to finish, and doesn't do any more reads. That seems quite brittle to me.

danbates2 commented 4 years ago

Guess that's why a non-blocking read is important for being able to stop/start emonhub or an interfacer.

TrystanLea commented 4 years ago

but I can't see how each interfacer is actually closed.

I think its just that the loop exits when it receives the flag and the interfacer closes automatically, I tried adding an additional close method above that would then have the ability to close a thread within an interfacer e.g by calling sds.del()

Looking at the code behind sds.del() it appears to only delete the socket, but we are not using sockets so I dont think it does anything..

danbates2 commented 4 years ago

I see what you mean... Like I say, I think the interfacer just doesn't do any more reads, it's not exiting the def read(). You see what I mean?

TrystanLea commented 4 years ago

In the case of SDS011 or more generally? Yes the original library was blocking during read()

danbates2 commented 4 years ago

Yes more generally. I mean emonhub isn't able to exit an interfacer's read(), instead it's dependent on it returning a value. So the blocking library caused a problem. I'm not fluent with this python anyway. I'm sure an expert would have implemented a blocking library better.

danbates2 commented 4 years ago

@TrystanLea I've changed the library and now everything is broken. It was working on my laptop with the sensor plugged in by usb, but not on the rpi. Not sure if command from previous library has put the sds011 on the rpi in some mode I'm not aware of. Shouldn't be the case. I've tried a few of the extra mode related functions from the new library. Or there's a datatype issue in emonhub I've missed.

if you're trying the new one :

$ sudo pip3 uninstall sds011 $ sudo pip3 install py-sds011

New problem too, if changing setting in emonhub it jamms up here:

 INFO     MainThread Deleting interfacer 'SDS011'
danbates2 commented 4 years ago

this is what I'm running on the laptop to test it. might help.

py-sds011-test.py.zip

danbates2 commented 4 years ago

@TrystanLea Got it. Try this one.

remember to uninstall the old module and install the new.

danbates2 commented 4 years ago

line 54: self.sensor.set_work_period(read=False, work_time=0) is what did it, set the mode of the sensor to something compatible with the new method.

danbates2 commented 4 years ago

@TrystanLea I've been testing the new methods for 24h and it's looking good.

TrystanLea commented 4 years ago

Thanks for this Dan, works a treat!

TrystanLea commented 4 years ago

PS: here's the code to optionally load the module https://github.com/openenergymonitor/emonhub/commit/db4e02cbc707c552818a021a84e3ffd5ae60aabe

danbates2 commented 4 years ago

Handy. Where did the sudo pip3 install py-sds011 command have to go in the end?