Code Monkey home page Code Monkey logo

pypms's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

pypms's Issues

capture and decode raw-data

raw sample data

The setup to capture raw data needed for #2 is a bit too involved for casual users.
For example, to capture SPS30 messages (47 bytes long) from /dev/ttyUSB0 one needs to

stty -F /dev/ttyUSB0 min 0 -icanon
tail -f /dev/ttyUSB0 | xxd -g1 -c47

The obscurity of the commands involved is not going to help gaining contributions for #2.
Besides the commands are slightly different for different sensors.

With the introduction of -n N, --samples N on #4, one can further extend the application to provide the raw data on the right format. The following would capture 10 messages, with a frequency of 15 seconds:

pms -s /dev/ttyUSB0 -m SPS30 -n 10 -i 15 raw

capture

Saving raw data to a file could be a good way to create sample data for testing.
This would provide a path to test the command line interface without real hardware attached.

pms -s /dev/ttyUSB0 -m SPS30 -n 10 -i 15 raw --capture

would write the raw data into a file with a well defined name pattern, e.g. start-time.pms. In the previous example, the file name would be something line 2020-01-01_15:22:23.pms

decode

Once we can capture raw data, caould decode it as

pms -s 2020-01-01_15:22:23.pms -m SPS30 -n 10 -i 15 raw --decode

The extension .pms would indicate that we are not reading from a serial port.
The start time is retrieved from the filename. The complete file would be decode if number of samples (-n) is not specified.

combining sub-commands

pms serial and pms csv have some overlap with pms raw-data. Maybe this 3 sub-commands can be rolled into one.
In addition to reducing the number of options, combining this sub-commands would help with the coverage on travis builds.

Consistent attribute names

For n attributes, the numbers are consistent, with _ representing the decimal.

For consistently and to make the numbers easier to understand, should the following change?

From To
raw01 raw1
raw25 raw2_5
pm01 pm1
pm25 pm2_5
pm04 pm4

Broken travis environment

The tests for python3.6 and 3.7 started failing at the install stage. Tests for python3.8 are passing fine.
Local tests work file for all python versions. I suspect something wrong with the travis config.
Asked on the forum for help...

Sensor output samples in documentation

The recently added sensor documentation contains raw output samples from all the sensors in my collection. However, as many of the supported sensors were implemented from the information available on the datasheets, the samples of the sensor output are missing.

Missing output samples, and any corrections to the documentation, are welcomed as a comment on this issue or as a PR.

A few lines of platformio device monitor -f hexlify would suffice, or even better xxd output as follows:

RPi zero with SDS198 reboots after running command

My pms instance seems to break after wake up SDS198
My sensor works fine as I am able to run it continuously on my laptop but on my RPi zero W it seems to crash when running the command: "pms -m SDS198 -s /dev/serial0 -i 2 -n 10 --debug serial"

pi@raspberrypi:~ $ pms -m SDS198 -s /dev/serial0 -i 2 -n 10 --debug serial
2023-07-06 15:46:23.447 | DEBUG    | pms.core.reader:__init__:109 - capture 10 SDS198 obs from /dev/serial0 every 2 secs
2023-07-06 15:46:23.464 | DEBUG    | pms.core.reader:open:143 - open /dev/serial0
2023-07-06 15:46:23.470 | DEBUG    | pms.core.reader:open:148 - wake SDS198

Is this a known bug? I am able to get a reading sometimes but when I want to try a second time, it breaks....

SPS30 to mosquitto socket error

Hei,

Using latest version of pms on ubuntu, I cannot make the mqtt connection to mosquitto 1.4.15 work:
pms -m SPS30 -n 1 -i 10 -s /dev/ttyUSB1 mqtt --mqtt-host localhost -t "test" throws no error, but I cannot subscribe to the feed.

mosquitto log indicates socket error:

1670442753: New client connected from 192.168.50.100 as test (c1, k60).
1670442769: Socket error on client test, disconnecting.

I have used pms serial and influx successfully for a long time, but for mqtt I could not get pms to work.

pms installed with pip: python3 -m pip install pypms[mqtt,influxdb]

pms: Command not found

Trying to use pypms on my rpi zero 2w
Installed using most recent version of pip.
The pms --help and pms serial commands do not work - they give the error bash: pms: command not found
I am not sure what I am missing - tried the commands as root and still do not work.
I am unfamiliar with python and raspberry pi in general so any help is appreciated, I am hoping to be able to read PM measurements from my Sensiron SPS30.

SDS198 wrong message header

Dear Alvaro,

I tried to connect a Nova SDS198 to my Rpi but it does not work. I also testet a Nova SDS011 and it works just fine!
Can you help me to bug fix?

Here is the dump from the debug mode:

pi@raspberrypi:~/Desktop/PyPMS $ /home/pi/.local/bin/pms -m SDS198 -s /dev/ttyUSB0 -i 10  --debug serial
DEBUG:pms:buffer length: 20
DEBUG:pms:Guess SDS198 from buffer contents
DEBUG:pms:message hex: aacf00000000e905eeab
DEBUG:pms:message header: b'\xaa\xcf'
DEBUG:pms:message hex: aacf00000000e905eeab
DEBUG:pms:message header: b'\xaa\xcf'
DEBUG:pms:message hex: aacf00000000e905eeab
DEBUG:pms:message header: b'\xaa\xcf'
DEBUG:pms:message hex: aacf00000000e905eeab
DEBUG:pms:message header: b'\xaa\xcf'
DEBUG:pms:message hex: aacf00000000e905eeab
DEBUG:pms:message header: b'\xaa\xcf'

Cheers, Alex

unreliably identifying the SPS30 sensor

When running the pms command, it seems to have trouble reliably identifying my SPS30 sensor. I can run it back to back a few times until the sensor is identified correctly and gives me readings. Here is example where it failed twice and worked the third time:

root@raspberrypi:/home/pi# pms -m SPS30 -n 3 -i 3 -s /dev/ttyAMA0 --debug serial -f csv
DEBUG:pms:capture 3 SPS30 obs from /dev/ttyAMA0 every 3 secs
DEBUG:pms:open /dev/ttyAMA0
DEBUG:pms:wake SPS30
DEBUG:pms:buffer length: 55
DEBUG:pms:message hex: 7e00004300bc7e7e0003002841204c59413a57fe4147f7e9414ab18542862e7d5e429d0205429fc71f42a04c1642a064f03f2b2c584c7e
DEBUG:pms:message hex: 7e0003002841204c59413a57fe4147f7e9414ab18542862e7d5e429d0205429fc71f42a04c1642a064f03f2b2c584c
ERROR:pms:Sensor is not SPS30
root@raspberrypi:/home/pi# pms -m SPS30 -n 3 -i 3 -s /dev/ttyAMA0 --debug serial -f csv
DEBUG:pms:capture 3 SPS30 obs from /dev/ttyAMA0 every 3 secs
DEBUG:pms:open /dev/ttyAMA0
DEBUG:pms:wake SPS30
DEBUG:pms:buffer length: 55
DEBUG:pms:message hex: 7e00004300bc7e7e000300284122a280413d479c414b47ec414e14c742887d3103429f438842a21ae142a2a35b42a2bcc83f2714e3b57e
DEBUG:pms:message hex: 7e000300284122a280413d479c414b47ec414e14c742887d3103429f438842a21ae142a2a35b42a2bcc83f2714e3b5
ERROR:pms:Sensor is not SPS30
root@raspberrypi:/home/pi# pms -m SPS30 -n 3 -i 3 -s /dev/ttyAMA0 --debug serial -f csv
DEBUG:pms:capture 3 SPS30 obs from /dev/ttyAMA0 every 3 secs
DEBUG:pms:open /dev/ttyAMA0
DEBUG:pms:wake SPS30
DEBUG:pms:buffer length: 54
DEBUG:pms:message hex: 7e00004300bc7e7e0003002841243d73413ef673414cf3b7414fbff94289782742a0dd0242a3b4df42a43d5d42a456dc3f23c6b63f7e
DEBUG:pms:message hex: 7e0003002841243d73413ef673414cf3b7414fbff94289782742a0dd0242a3b4df42a43d5d42a456dc3f23c6b63f7e
DEBUG:pms:message payload: (10.265002250671387, 11.935168266296387, 12.809500694274902, 12.984368324279785, 68.73467254638672, 80.43165588378906, 81.85326385498047, 82.1198501586914, 82.16964721679688, 0.6397508382797241)
DEBUG:pms:message hex: 7e00030000fc7e
DEBUG:pms:message header: b'~\x00\x03\x00\x00'
DEBUG:pms:message hex: 7e00030028411d271d41368ea94143cf3f414675c0428397334299f243429ca4c7429d2635429d3e703f26a0730f7e
DEBUG:pms:message payload: (9.822049140930176, 11.409829139709473, 12.238097190856934, 12.40374755859375, 65.7953109741211, 76.9731674194336, 78.32183074951172, 78.57462310791016, 78.6219482421875, 0.6508857607841492)
time, pm01, pm25, pm04, pm10, n0_5, n1_0, n2_5, n4_0, n10_0, diam
1630355654, 9.8, 11.4, 12.2, 12.4, 65.80, 76.97, 78.32, 78.57, 78.62, 0.7
DEBUG:pms:message hex: 7e00030028411a411e4132fe45413fd7694142693442813a33429722e84299c197429a3f3b429a56d23f26ef40507e
DEBUG:pms:message payload: (9.640897750854492, 11.187077522277832, 11.990090370178223, 12.150684356689453, 64.6136703491211, 75.56817626953125, 76.87810516357422, 77.12349700927734, 77.16957092285156, 0.6520881652832031)
1630355657, 9.6, 11.2, 12.0, 12.2, 64.61, 75.57, 76.88, 77.12, 77.17, 0.7
DEBUG:pms:message hex: 7e00030028411ab0ca41334971413fffe441428ac64281a95542979869429a3159429aadd5429ac5463f27ae40017e
DEBUG:pms:message payload: (9.668161392211914, 11.205430030822754, 11.99997329711914, 12.158880233764648, 64.83072662353516, 75.79767608642578, 77.09638214111328, 77.33951568603516, 77.38529968261719, 0.6550025939941406)
1630355660, 9.7, 11.2, 12.0, 12.2, 64.83, 75.80, 77.10, 77.34, 77.39, 0.7
DEBUG:pms:sleep SPS30
DEBUG:pms:close /dev/ttyAMA0

Here is another time it errored where the initial response from the sensor was much shorter:

root@raspberry:/home/pi# pms -m SPS30 -n 3 -i 3 -s /dev/ttyAMA0 --debug serial -f csv
DEBUG:pms:capture 3 SPS30 obs from /dev/ttyAMA0 every 3 secs
DEBUG:pms:open /dev/ttyAMA0
DEBUG:pms:wake SPS30
DEBUG:pms:buffer length: 14
DEBUG:pms:message hex: 7e00000000ff7e7e00030000fc7e
ERROR:pms:Sensor is not SPS30

I should be able to work around this by capturing the error and looping the command until I get some kind of expected results, but maybe the SPS30 has been updated and has some new identifiers? I do see the buffer length was 54 when it worked vs the 55 and 14 seen previously. No idea what might be going on.

Hardware: Raspberry Pi model B rev 2
OS: Raspbian GNU/Linux 10 (buster)
SPS30: attached to UART interface on pi (serial RX/TX, pins 8 and 10) and +5v and ground

Help to set up mqtt

Hello.

Can you tell me, how can I setup the mqtt, because there is nothing about it in the readme? I would like to send the information to my local broker, but I have no idea how can I tell to pms what is the mqtt broker address, port, topic (the user and password is clear, because it can set as variable). On the other site I want to use Domoticz to log the details...

Thanks

List all possible reader attributes in the README

It'd be helpful to have a list of all possible attributes a reading could have, so that I can ensure I have a database column for each one and can fully support all sensors in this package, particularly as the scope now includes a variety of sensor types. I couldn't find this in a single file anywhere, so might fit best in the readme.

PMS5003T not recognized

Hello.

I try to use your program with a PMS5003T sensor. Unfortunately not recognized. Can you help me what should be the problem?

pms -m PMS5003T -s /dev/ttyAMA0 --debug info
DEBUG:pms:capture ? PMS5003T obs from /dev/ttyAMA0 every 60 secs

    Plantower PMS5003T sensor observations

    time                                    measurement time [seconds since epoch]
    raw01, raw25, raw10                     cf=1 PM estimates [μg/m3]
    pm01, pm25, pm10                        PM1.0, PM2.5, PM10 [μg/m3]
    n0_3, n0_5, n1_0, n2_5                  number concentrations over X.Y um [#/cm3]
    temp                                    temperature [°C]
    rhum                                    relative humidity [%]

    String formats: pm (default), raw, cf, num, atm, csv and header
pms -m PMS5003T -s /dev/ttyAMA0 --debug serial
DEBUG:pms:capture ? PMS5003T obs from /dev/ttyAMA0 every 60 secs
DEBUG:pms:open /dev/ttyAMA0
DEBUG:pms:wake PMS5003T
DEBUG:pms:buffer length: 47
DEBUG:pms:message hex: 1c000b00110011000b001100110742004d001c000a00100010000a0010001007bc024a0076000800d700e39a0004e0
ERROR:pms:Sensor is not PMS5003T

The sensor itself working, because I testing it with this:
https://github.com/pjq/rpi

./monitor.sh
start monitor pm2.5...
loop times 0
http://127.0.0.1:8080/api/weather
{"lat": 0, "date": "Mon Feb  1 13:44:06 2021", "alt": 0, "temperature": 21.8, "pm10": 16, "raw_data": "", "humidity": 22.9, "pm25_cf": 16, "location": "home", "pm10_cf": 16, "pm25": 16}

Thanks

Cannot read HPMA115C0

Hi,
There are some issues while trying to connect to this PM sensor:

commands = hpma115s0.commands._replace(
    passive_read=base.Cmd(  # Read Particle Measuring Results
        b"\x68\x01\x04\x93", b"\x40\x0d\x04", 16
    )
)

The length of the packet is 16 bytes, hence the second byte of the response should be 0x0D ... The datasheet seems to be wrong...

Also, when receiving the ack from passive mode command it fails (wrong header length - it receives 0xA5 0xA5) - it is validated as a message (in s0 _validate)...

diff --git a/src/pms/sensors/honeywell/hpma115c0.py b/src/pms/sensors/honeywell/hpma115c0.py
index b662658..4bcc6bb 100644
--- a/src/pms/sensors/honeywell/hpma115c0.py
+++ b/src/pms/sensors/honeywell/hpma115c0.py
@@ -11,7 +11,7 @@ from . import hpma115s0
 
 commands = hpma115s0.commands._replace(
     passive_read=base.Cmd(  # Read Particle Measuring Results
-        b"\x68\x01\x04\x93", b"\x40\x05\x04", 16
+        b"\x68\x01\x04\x93", b"\x40\x0d\x04", 16
     )
 )
 
@@ -21,6 +21,10 @@ class Message(hpma115s0.Message):
 
     data_records = slice(4)
 
+    @classmethod
+    def _validate(cls, message: bytes, header: bytes, length: int) -> base.Message:
+        return cls(message)
+
 
 @dataclass(frozen=False)
 class ObsData(base.ObsData):

It is not a fix, but at least I was able to take a sample

$ pms -s /dev/ttyUSB0 -m HPMA115C0 -n 10 -i 15 serial -f hexdump
00000000: 40 0d 04 00 04 00 07 00 09 00 17 00 00 00 00 84  @...............
00000010: 40 0d 04 00 03 00 04 00 04 00 04 00 00 00 00 a0  @...............
00000020: 40 0d 04 00 04 00 06 00 06 00 07 00 00 00 00 98  @...............
00000030: 40 0d 04 00 05 00 06 00 06 00 07 00 00 00 00 97  @...............
00000040: 40 0d 04 00 04 00 05 00 05 00 05 00 00 00 00 9c  @...............
00000050: 40 0d 04 00 05 00 06 00 06 00 08 00 00 00 00 96  @...............
00000060: 40 0d 04 00 05 00 07 00 07 00 08 00 00 00 00 94  @...............
00000070: 40 0d 04 00 05 00 07 00 07 00 08 00 00 00 00 94  @...............
00000080: 40 0d 04 00 04 00 06 00 06 00 07 00 00 00 00 98  @...............
00000090: 40 0d 04 00 04 00 06 00 07 00 08 00 00 00 00 96  @...............

Discard invalid observations after wake up

Plantower sensors have a quirk

On my tests I found out that it is not enough to wait some time before reading from a sensor who just woke up. The sensor needs to be "exercised" a few times before the measurements become meaningful.
After a sleep/wake up cycle, the sensor the first few readings have non zero PM values but all the number concentrations are zero. IMO, this observations should be discarded so I'm considering to add an --strict option for this. I have not observed the problem when the modules are just powered up.

Originally posted by @avaldebe in #1 (comment)

This quirk is not present after power cycling and on most cases the first observations after wake up can be discarded on post processing. However, if the sensors are read on "one-shot" mode as requested on #1, these kind of inconsistent observations need to be discarded.

The new option --strict will take care of this kind of inconsistent observations.

Questions & Suggestions

Hi

Are you planning to add functionality to:

  1. Allow a python app to easily create and read multiple sensor instances?
  2. Allow readings on demand, returning readings in an appropriate structure, so that the timing and storing of data can be managed by the python app using PyPMS?

Would be very handy having a single package that supports so many sensors!

Also, do you make use of the SET and RESET pins on the PMSA003?

Thanks

Stop after a number of readings and "one-shot" mode

From #1

  1. Allow readings on demand, returning readings in an appropriate structure, so that the timing and storing of data can be managed by the python app using PyPMS?

A more general use case would be to stop the data acquisition after a number successful observations. Two new options will be introduced:

  • -n N, --samples N: stop the data acquisition after N successful observations.
  • --one-shot equivalent to -n1 --strict, where --strict takes care of invalid observations after wake up (as discussed on #1 and #3).

PMS5003T/PMS5003ST signed temperature

Just found out a English datasheet for the PMS5003ST, which says that the temperature is a signed integer. This total sense as the temperature can be negative.

Alas, the _unpack unpack method inhereted from PMS3003 decodes the message as unsigned integers.

@staticmethod
def _unpack(message: bytes) -> Tuple[int, ...]:
return struct.unpack(f">{len(message)//2}H", message)

Therefore, negative temperatures will show as huge values.

pip3 module not found

Hello.

I trying to install this module on my raspberry pi Debian 9.11, Python 3.5.3, but it is not found :( .

pip3 install pypms

Collecting pypms
Could not find a version that satisfies the requirement pypms (from versions: )
No matching distribution found for pypms

Can you help me how can i install and use it in this system?

Thanks

MCU680 obs.pres typo

the data pressure field is called pres, not press

pres: float = field(metadata=base.metadata("atmospheric pressure", "hPa", "pressure"))

__post_init__ should update pres, but instead it creates an attribute press

self.press = (int(self.pres) << 8 | self.IAQ_acc) / 100

__format__ uses press instead of pres, which hides the error

if spec == "atm":
return f"{self.date:%F %T}: Temp. {self.temp:.1f} °C, Rel.Hum. {self.rhum:.1f} %, Press {self.press:.2f} hPa"
if spec == "bme":
return f"{self.date:%F %T}: Temp. {self.temp:.1f} °C, Rel.Hum. {self.rhum:.1f} %, Press {self.press:.2f} hPa, {self.gas:.1f} kΩ"
if spec == "bsec":
return f"{self.date:%F %T}: Temp. {self.temp:.1f} °C, Rel.Hum. {self.rhum:.1f} %, Press {self.press:.2f} hPa, {self.IAQ} IAQ"
if spec == "csv":
return f"{self.time}, {self.temp:.1f}, {self.rhum:.1f}, {self.press:.2f}, {self.IAQ_acc}, {self.IAQ}, {self.gas:.1f}, {self.alt}"

logging.basicConfig() conflicts with use as a library

Great codebase - really helpful to have all this knowledge in one place!

I've started using pms as a library in my own project. A small problem I encountered is this line, which means I have to use force=True when I call logging.basicConfig in order for it to pick up my preferred settings.

Would it be possible to move that line to the pms.cli module? I reckon that should preserve the existing behaviour for CLI users. Happy to make a PR for it but thought it would be best to ask first.

Add to pypi

So that it can be more easily discovered and then installed with PIP

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.