diff --git a/diagrams/README.md b/diagrams/README.md new file mode 100644 index 0000000..5363cc4 --- /dev/null +++ b/diagrams/README.md @@ -0,0 +1,9 @@ +# Diagrams + +This directory contains design diagrams. + +## Auto Generate UML + +```bash +pyreverse -d . -o png ../purpleair_data_logger +``` \ No newline at end of file diff --git a/diagrams/classes.png b/diagrams/classes.png new file mode 100644 index 0000000..6a5a3e5 Binary files /dev/null and b/diagrams/classes.png differ diff --git a/diagrams/packages.png b/diagrams/packages.png new file mode 100644 index 0000000..f158a65 Binary files /dev/null and b/diagrams/packages.png differ diff --git a/hardware_variant_json_samples/1.0+1M+PMSX003-O.json b/external_network_hardware_variant_json_samples/1.0+1M+PMSX003-O.json similarity index 100% rename from hardware_variant_json_samples/1.0+1M+PMSX003-O.json rename to external_network_hardware_variant_json_samples/1.0+1M+PMSX003-O.json diff --git a/hardware_variant_json_samples/2.0+1M+PMSX003-A.json b/external_network_hardware_variant_json_samples/2.0+1M+PMSX003-A.json similarity index 100% rename from hardware_variant_json_samples/2.0+1M+PMSX003-A.json rename to external_network_hardware_variant_json_samples/2.0+1M+PMSX003-A.json diff --git a/external_network_hardware_variant_json_samples/2.0+BME280+PMSX003-A.json b/external_network_hardware_variant_json_samples/2.0+BME280+PMSX003-A.json new file mode 100644 index 0000000..5b58094 --- /dev/null +++ b/external_network_hardware_variant_json_samples/2.0+BME280+PMSX003-A.json @@ -0,0 +1,106 @@ +{ + "api_version": "V1.0.11-0.0.49", + "time_stamp": 1695569096, + "data_time_stamp": 1695569064, + "sensor": { + "sensor_index": 163965, + "last_modified": 1664215336, + "date_created": 1663784441, + "last_seen": 1695568955, + "private": 0, + "is_owner": 0, + "name": "carlkidcrypto-purpleair2", + "icon": 0, + "location_type": 1, + "model": "PA-I", + "hardware": "2.0+BME280+PMSX003-A", + "led_brightness": 100, + "firmware_version": "7.02", + "rssi": -75, + "uptime": 69901, + "pa_latency": 943, + "memory": 15944, + "position_rating": 5, + "latitude": 46.74709, + "longitude": -116.998924, + "altitude": 2647, + "channel_state": 1, + "channel_flags": 0, + "channel_flags_manual": 0, + "channel_flags_auto": 0, + "confidence": 30, + "humidity": 31, + "humidity_a": 31, + "temperature": 79, + "temperature_a": 79, + "pressure": 923.43, + "pressure_a": 923.43, + "analog_input": 0.0, + "pm1.0": 2.6, + "pm1.0_a": 2.6, + "pm2.5": 4.4, + "pm2.5_a": 4.4, + "pm2.5_alt": 3.4, + "pm2.5_alt_a": 3.4, + "pm10.0": 4.4, + "pm10.0_a": 4.4, + "scattering_coefficient": 10.4, + "scattering_coefficient_a": 10.4, + "deciviews": 8.1, + "deciviews_a": 8.1, + "visual_range": 173.8, + "visual_range_a": 173.8, + "0.3_um_count": 691, + "0.3_um_count_a": 691, + "0.5_um_count": 178, + "0.5_um_count_a": 178, + "1.0_um_count": 35, + "1.0_um_count_a": 35, + "2.5_um_count": 0, + "2.5_um_count_a": 0, + "5.0_um_count": 0, + "5.0_um_count_a": 0, + "10.0_um_count": 0, + "10.0_um_count_a": 0, + "pm1.0_cf_1": 2.6, + "pm1.0_cf_1_a": 2.61, + "pm1.0_atm": 2.6, + "pm1.0_atm_a": 2.61, + "pm2.5_atm": 4.4, + "pm2.5_atm_a": 4.35, + "pm2.5_cf_1": 4.4, + "pm2.5_cf_1_a": 4.35, + "pm10.0_atm": 4.4, + "pm10.0_atm_a": 4.35, + "pm10.0_cf_1": 4.4, + "pm10.0_cf_1_a": 4.35, + "primary_id_a": 1868567, + "primary_key_a": "3XJ73Z60EX66XSHH", + "primary_id_b": 1868571, + "primary_key_b": "4TZ413W55H4ZCXMB", + "secondary_id_a": 1868569, + "secondary_key_a": "H8X58IEXEOBAPMQY", + "secondary_id_b": 1868573, + "secondary_key_b": "TWNBKVZZDWFMWSPV", + "stats": { + "pm2.5": 4.4, + "pm2.5_10minute": 4.2, + "pm2.5_30minute": 4.2, + "pm2.5_60minute": 4.1, + "pm2.5_6hour": 4.2, + "pm2.5_24hour": 2.5, + "pm2.5_1week": 3.5, + "time_stamp": 1695568955 + }, + "stats_a": { + "pm2.5": 4.4, + "pm2.5_10minute": 4.2, + "pm2.5_30minute": 4.2, + "pm2.5_60minute": 4.1, + "pm2.5_6hour": 4.2, + "pm2.5_24hour": 2.5, + "pm2.5_1week": 3.5, + "time_stamp": 1695568955 + } + } +} \ No newline at end of file diff --git a/hardware_variant_json_samples/2.0+BME280+PMSX003-B+PMSX003-A.json b/external_network_hardware_variant_json_samples/2.0+BME280+PMSX003-B+PMSX003-A.json similarity index 100% rename from hardware_variant_json_samples/2.0+BME280+PMSX003-B+PMSX003-A.json rename to external_network_hardware_variant_json_samples/2.0+BME280+PMSX003-B+PMSX003-A.json diff --git a/hardware_variant_json_samples/2.0+OPENLOG+31037 MB+DS3231+BME280+PMSX003-A.json b/external_network_hardware_variant_json_samples/2.0+OPENLOG+31037 MB+DS3231+BME280+PMSX003-A.json similarity index 100% rename from hardware_variant_json_samples/2.0+OPENLOG+31037 MB+DS3231+BME280+PMSX003-A.json rename to external_network_hardware_variant_json_samples/2.0+OPENLOG+31037 MB+DS3231+BME280+PMSX003-A.json diff --git a/hardware_variant_json_samples/2.0+OPENLOG+31037 MB+DS3231+BME280+PMSX003-B+PMSX003-A.json b/external_network_hardware_variant_json_samples/2.0+OPENLOG+31037 MB+DS3231+BME280+PMSX003-B+PMSX003-A.json similarity index 100% rename from hardware_variant_json_samples/2.0+OPENLOG+31037 MB+DS3231+BME280+PMSX003-B+PMSX003-A.json rename to external_network_hardware_variant_json_samples/2.0+OPENLOG+31037 MB+DS3231+BME280+PMSX003-B+PMSX003-A.json diff --git a/hardware_variant_json_samples/3.0+BME280+BME680+PMSX003-A.json b/external_network_hardware_variant_json_samples/3.0+BME280+BME680+PMSX003-A.json similarity index 100% rename from hardware_variant_json_samples/3.0+BME280+BME680+PMSX003-A.json rename to external_network_hardware_variant_json_samples/3.0+BME280+BME680+PMSX003-A.json diff --git a/external_network_hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME68X+PMSX003-A+PMSX003-B.json b/external_network_hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME68X+PMSX003-A+PMSX003-B.json new file mode 100644 index 0000000..460128a --- /dev/null +++ b/external_network_hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME68X+PMSX003-A+PMSX003-B.json @@ -0,0 +1,142 @@ +{ + "api_version": "V1.0.11-0.0.49", + "time_stamp": 1695569392, + "data_time_stamp": 1695569365, + "sensor": { + "sensor_index": 123456, + "last_modified": 1656033161, + "date_created": 1653666655, + "last_seen": 1695569319, + "private": 0, + "is_owner": 0, + "name": "A NAME GOES HERE", + "icon": 0, + "location_type": 0, + "model": "PA-II-FLEX", + "hardware": "3.0+OPENLOG+31037 MB+DS3231+BME280+BME68X+PMSX003-A+PMSX003-B", + "led_brightness": 100, + "firmware_version": "7.04", + "rssi": -62, + "uptime": 137, + "pa_latency": 732, + "memory": 5672, + "position_rating": 5, + "latitude": 123.123, + "longitude": -123.123, + "altitude": 123, + "channel_state": 3, + "channel_flags": 0, + "channel_flags_manual": 0, + "channel_flags_auto": 0, + "confidence": 100, + "confidence_auto": 100, + "confidence_manual": 100, + "humidity": 46, + "humidity_a": 44, + "humidity_b": 49, + "temperature": 63, + "temperature_a": 64, + "temperature_b": 62, + "pressure": 924.6, + "pressure_a": 925.33, + "pressure_b": 923.87, + "voc": 598.9, + "voc_b": 598.89, + "analog_input": 0.06, + "pm1.0": 23.7, + "pm1.0_a": 23.3, + "pm1.0_b": 24.0, + "pm2.5": 34.7, + "pm2.5_a": 35.0, + "pm2.5_b": 34.5, + "pm2.5_alt": 22.1, + "pm2.5_alt_a": 23.2, + "pm2.5_alt_b": 21.1, + "pm10.0": 44.4, + "pm10.0_a": 46.7, + "pm10.0_b": 42.0, + "scattering_coefficient": 70.1, + "scattering_coefficient_a": 70.1, + "scattering_coefficient_b": 70.1, + "deciviews": 22.4, + "deciviews_a": 22.4, + "deciviews_b": 22.4, + "visual_range": 41.5, + "visual_range_a": 41.5, + "visual_range_b": 41.4, + "0.3_um_count": 4671, + "0.3_um_count_a": 4671, + "0.3_um_count_b": 4672, + "0.5_um_count": 1330, + "0.5_um_count_a": 1330, + "0.5_um_count_b": 1330, + "1.0_um_count": 230, + "1.0_um_count_a": 253, + "1.0_um_count_b": 208, + "2.5_um_count": 21, + "2.5_um_count_a": 25, + "2.5_um_count_b": 18, + "5.0_um_count": 9, + "5.0_um_count_a": 11, + "5.0_um_count_b": 7, + "10.0_um_count": 4, + "10.0_um_count_a": 9, + "10.0_um_count_b": 0, + "pm1.0_cf_1": 27.0, + "pm1.0_cf_1_a": 26.48, + "pm1.0_cf_1_b": 27.53, + "pm1.0_atm": 23.7, + "pm1.0_atm_a": 23.34, + "pm1.0_atm_b": 23.98, + "pm2.5_atm": 34.7, + "pm2.5_atm_a": 34.95, + "pm2.5_atm_b": 34.46, + "pm2.5_cf_1": 38.1, + "pm2.5_cf_1_a": 38.61, + "pm2.5_cf_1_b": 37.56, + "pm10.0_atm": 44.4, + "pm10.0_atm_a": 46.68, + "pm10.0_atm_b": 42.05, + "pm10.0_cf_1": 45.2, + "pm10.0_cf_1_a": 48.2, + "pm10.0_cf_1_b": 42.2, + "primary_id_a": 1750199, + "primary_key_a": "M9M66UHOIS8YIAGH", + "primary_id_b": 1750201, + "primary_key_b": "D9M2N0ZO81PTA210", + "secondary_id_a": 1750200, + "secondary_key_a": "O4T8GWNDUROR5EP6", + "secondary_id_b": 1750202, + "secondary_key_b": "2YTJ6VA9HS3T8K07", + "stats": { + "pm2.5": 34.7, + "pm2.5_10minute": 31.6, + "pm2.5_30minute": 32.2, + "pm2.5_60minute": 32.5, + "pm2.5_6hour": 22.2, + "pm2.5_24hour": 13.6, + "pm2.5_1week": 9.9, + "time_stamp": 1695569319 + }, + "stats_a": { + "pm2.5": 35.0, + "pm2.5_10minute": 32.0, + "pm2.5_30minute": 32.5, + "pm2.5_60minute": 32.8, + "pm2.5_6hour": 22.3, + "pm2.5_24hour": 13.6, + "pm2.5_1week": 9.8, + "time_stamp": 1695569319 + }, + "stats_b": { + "pm2.5": 34.5, + "pm2.5_10minute": 31.3, + "pm2.5_30minute": 31.8, + "pm2.5_60minute": 32.2, + "pm2.5_6hour": 22.1, + "pm2.5_24hour": 13.5, + "pm2.5_1week": 9.9, + "time_stamp": 1695569319 + } + } +} \ No newline at end of file diff --git a/external_network_hardware_variant_json_samples/README.md b/external_network_hardware_variant_json_samples/README.md new file mode 100644 index 0000000..4731e29 --- /dev/null +++ b/external_network_hardware_variant_json_samples/README.md @@ -0,0 +1,4 @@ +# External Network Hardware Variant Json Samples + +This directory contains responses from different devices (hardware variants) that +are publical accessible via the Purpleair API. \ No newline at end of file diff --git a/hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME680+PMSX003-A+PMSX003-B.json b/hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME680+PMSX003-A+PMSX003-B.json deleted file mode 100644 index b7c96e3..0000000 --- a/hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME680+PMSX003-A+PMSX003-B.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "api_version": "V1.0.11-0.0.31", - "time_stamp": 1658811272, - "data_time_stamp": 1658811226, - "sensor": { - "sensor_index": 147883, - "last_modified": 1656033161, - "date_created": 1653666655, - "last_seen": 1658811136, - "private": 0, - "is_owner": 0, - "name": "carlkidcrypto-purpleair", - "icon": 0, - "location_type": 0, - "model": "PA-II-FLEX", - "hardware": "3.0+OPENLOG+31037 MB+DS3231+BME280+BME680+PMSX003-A+PMSX003-B", - "led_brightness": 100, - "firmware_version": "7.00", - "rssi": -63, - "uptime": 32951, - "pa_latency": 694, - "memory": 15448, - "position_rating": 5, - "latitude": 46.747154, - "longitude": -116.998795, - "altitude": 2644, - "channel_state": 3, - "channel_flags": 0, - "channel_flags_manual": 0, - "channel_flags_auto": 0, - "confidence": 100, - "confidence_auto": 100, - "confidence_manual": 100, - "humidity": 37, - "humidity_a": 37, - "humidity_b": 38, - "temperature": 77, - "temperature_a": 77, - "temperature_b": 77, - "pressure": 921.45, - "pressure_a": 921.81, - "pressure_b": 921.1, - "voc": 93.0, - "voc_b": 92.98, - "analog_input": 0.06, - "pm1.0": 6.5, - "pm1.0_a": 5.7, - "pm1.0_b": 7.3, - "pm2.5": 8.2, - "pm2.5_a": 7.0, - "pm2.5_b": 9.4, - "pm2.5_alt": 5.1, - "pm2.5_alt_a": 4.8, - "pm2.5_alt_b": 5.4, - "pm10.0": 9.2, - "pm10.0_a": 7.7, - "pm10.0_b": 10.6, - "scattering_coefficient": 20.2, - "scattering_coefficient_a": 19.0, - "scattering_coefficient_b": 21.4, - "deciviews": 12.3, - "deciviews_a": 11.9, - "deciviews_b": 12.7, - "visual_range": 113.9, - "visual_range_a": 118.7, - "visual_range_b": 109.1, - "0.3_um_count": 1350, - "0.3_um_count_a": 1270, - "0.3_um_count_b": 1430, - "0.5_um_count": 372, - "0.5_um_count_a": 351, - "0.5_um_count_b": 393, - "1.0_um_count": 41, - "1.0_um_count_a": 38, - "1.0_um_count_b": 44, - "2.5_um_count": 3, - "2.5_um_count_a": 2, - "2.5_um_count_b": 4, - "5.0_um_count": 0, - "5.0_um_count_a": 0, - "5.0_um_count_b": 1, - "10.0_um_count": 0, - "10.0_um_count_a": 0, - "10.0_um_count_b": 0, - "pm1.0_cf_1": 6.5, - "pm1.0_cf_1_a": 5.69, - "pm1.0_cf_1_b": 7.32, - "pm1.0_atm": 6.5, - "pm1.0_atm_a": 5.69, - "pm1.0_atm_b": 7.32, - "pm2.5_atm": 8.2, - "pm2.5_atm_a": 7.0, - "pm2.5_atm_b": 9.38, - "pm2.5_cf_1": 8.2, - "pm2.5_cf_1_a": 7.0, - "pm2.5_cf_1_b": 9.38, - "pm10.0_atm": 9.2, - "pm10.0_atm_a": 7.68, - "pm10.0_atm_b": 10.62, - "pm10.0_cf_1": 9.2, - "pm10.0_cf_1_a": 7.68, - "pm10.0_cf_1_b": 10.62, - "primary_id_a": 1750199, - "primary_key_a": "M9M66UHOIS8YIAGH", - "primary_id_b": 1750201, - "primary_key_b": "D9M2N0ZO81PTA210", - "secondary_id_a": 1750200, - "secondary_key_a": "O4T8GWNDUROR5EP6", - "secondary_id_b": 1750202, - "secondary_key_b": "2YTJ6VA9HS3T8K07", - "stats": { - "pm2.5": 8.2, - "pm2.5_10minute": 8.4, - "pm2.5_30minute": 8.0, - "pm2.5_60minute": 7.3, - "pm2.5_6hour": 6.2, - "pm2.5_24hour": 4.9, - "pm2.5_1week": 3.5, - "time_stamp": 1658811136 - }, - "stats_a": { - "pm2.5": 7.0, - "pm2.5_10minute": 7.5, - "pm2.5_30minute": 7.1, - "pm2.5_60minute": 6.4, - "pm2.5_6hour": 5.5, - "pm2.5_24hour": 4.3, - "pm2.5_1week": 3.2, - "time_stamp": 1658811136 - }, - "stats_b": { - "pm2.5": 9.4, - "pm2.5_10minute": 9.4, - "pm2.5_30minute": 9.0, - "pm2.5_60minute": 8.2, - "pm2.5_6hour": 7.0, - "pm2.5_24hour": 5.5, - "pm2.5_1week": 3.8, - "time_stamp": 1658811136 - } - } -} \ No newline at end of file diff --git a/internal_network_hardware_variant_json_samples/2.0+BME280+PMSX003-A.json b/internal_network_hardware_variant_json_samples/2.0+BME280+PMSX003-A.json new file mode 100644 index 0000000..9490ffd --- /dev/null +++ b/internal_network_hardware_variant_json_samples/2.0+BME280+PMSX003-A.json @@ -0,0 +1,57 @@ +{ + "SensorId": "de:ad:be:ef:12:34", + "DateTime": "2023/09/22T16:04:07z", + "Geo": "PurpleAir-1234", + "Mem": 15920, + "memfrag": 20, + "memfb": 12792, + "memcs": 704, + "Id": 67045, + "lat": 123.123, + "lon": -123.123, + "Adc": 0.0, + "loggingrate": 15, + "place": "inside", + "version": "7.02", + "uptime": 4023791, + "rssi": -62, + "period": 120, + "httpsuccess": 68136, + "httpsends": 68163, + "hardwareversion": "2.0", + "hardwarediscovered": "2.0+BME280+PMSX003-A", + "current_temp_f": 79, + "current_humidity": 31, + "current_dewpoint_f": 46, + "pressure": 924.57, + "p25aqic": "rgb(0,228,0)", + "pm2.5_aqi": 0, + "pm1_0_cf_1": 0.0, + "p_0_3_um": 147.71, + "pm2_5_cf_1": 0.04, + "p_0_5_um": 39.61, + "pm10_0_cf_1": 0.44, + "p_1_0_um": 5.63, + "pm1_0_atm": 0.0, + "p_2_5_um": 0.81, + "pm2_5_atm": 0.04, + "p_5_0_um": 0.43, + "pm10_0_atm": 0.44, + "p_10_0_um": 0.43, + "pa_latency": 1112, + "response": 401, + "response_date": 1695398528, + "latency": 289, + "wlstate": "Connected", + "status_0": 2, + "status_1": 2, + "status_2": 2, + "status_3": 2, + "status_4": 0, + "status_5": 0, + "status_6": 3, + "status_7": 0, + "status_8": 0, + "status_9": 0, + "ssid": "WIFI-NAME-GOES-HERE" +} \ No newline at end of file diff --git a/internal_network_hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME68X+PMSX003-A+PMSX003-B.json b/internal_network_hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME68X+PMSX003-A+PMSX003-B.json new file mode 100644 index 0000000..11fbf59 --- /dev/null +++ b/internal_network_hardware_variant_json_samples/3.0+OPENLOG+31037 MB+DS3231+BME280+BME68X+PMSX003-A+PMSX003-B.json @@ -0,0 +1,76 @@ +{ + "SensorId": "de:ad:be:ef:12:34", + "DateTime": "2023/09/22T16:04:16z", + "Geo": "PurpleAir-1234", + "Mem": 10016, + "memfrag": 21, + "memfb": 7848, + "memcs": 352, + "Id": 3380, + "lat": 123.123, + "lon": -123.123, + "Adc": 0.06, + "loggingrate": 15, + "place": "outside", + "version": "7.04", + "uptime": 404647, + "rssi": -57, + "period": 120, + "httpsuccess": 6854, + "httpsends": 6855, + "hardwareversion": "3.0", + "hardwarediscovered": "3.0+OPENLOG+31037 MB+DS3231+BME280+BME68X+PMSX003-A+PMSX003-B", + "current_temp_f": 59, + "current_humidity": 58, + "current_dewpoint_f": 44, + "pressure": 926.79, + "current_temp_f_680": 57, + "current_humidity_680": 64, + "current_dewpoint_f_680": 45, + "pressure_680": 925.21, + "gas_680": 282.68, + "p25aqic_b": "rgb(151,244,0)", + "pm2.5_aqi_b": 42, + "pm1_0_cf_1_b": 6.9, + "p_0_3_um_b": 1261.03, + "pm2_5_cf_1_b": 10.07, + "p_0_5_um_b": 356.72, + "pm10_0_cf_1_b": 10.78, + "p_1_0_um_b": 71.19, + "pm1_0_atm_b": 6.9, + "p_2_5_um_b": 3.76, + "pm2_5_atm_b": 10.07, + "p_5_0_um_b": 0.38, + "pm10_0_atm_b": 10.78, + "p_10_0_um_b": 0.38, + "p25aqic": "rgb(199,249,0)", + "pm2.5_aqi": 46, + "pm1_0_cf_1": 6.55, + "p_0_3_um": 1310.69, + "pm2_5_cf_1": 10.98, + "p_0_5_um": 378.66, + "pm10_0_cf_1": 12.52, + "p_1_0_um": 80.79, + "pm1_0_atm": 6.55, + "p_2_5_um": 7.24, + "pm2_5_atm": 10.98, + "p_5_0_um": 1.62, + "pm10_0_atm": 12.52, + "p_10_0_um": 0.84, + "pa_latency": 777, + "response": 401, + "response_date": 1695398572, + "latency": 751, + "wlstate": "Connected", + "status_0": 2, + "status_1": 2, + "status_2": 2, + "status_3": 2, + "status_4": 2, + "status_5": 2, + "status_6": 3, + "status_7": 0, + "status_8": 2, + "status_9": 2, + "ssid": "WIFI-NAME-GOES-HERE" +} \ No newline at end of file diff --git a/internal_network_hardware_variant_json_samples/README.md b/internal_network_hardware_variant_json_samples/README.md new file mode 100644 index 0000000..7e7b7b3 --- /dev/null +++ b/internal_network_hardware_variant_json_samples/README.md @@ -0,0 +1,4 @@ +# Internal Network Hardware Variant Json Samples + +This directory contains response from different devices (hardware variants) that +are privatley accessible via the local network Purpleair API. \ No newline at end of file diff --git a/purpleair_data_logger/PurpleAirCSVDataLogger.py b/purpleair_data_logger/PurpleAirCSVDataLogger.py index e661a75..88ff357 100644 --- a/purpleair_data_logger/PurpleAirCSVDataLogger.py +++ b/purpleair_data_logger/PurpleAirCSVDataLogger.py @@ -47,16 +47,24 @@ class PurpleAirCSVDataLogger(PurpleAirDataLogger): """ def __init__( - self, PurpleAirAPIReadKey, PurpleAirAPIWriteKey, path_to_save_csv_files_in + self, + PurpleAirApiReadKey=None, + PurpleAirApiWriteKey=None, + PurpleAirApiIpv4Address=None, + path_to_save_csv_files_in=None, ): """ - :param str PurpleAirAPIReadKey: A valid PurpleAirAPI Read key + :param str PurpleAirApiReadKey: A valid PurpleAirAPI Read key + :param str PurpleAirApiWriteKey: A valid PurpleAirAPI Write key + :param list PurpleAirApiIpv4Address: A list of valid IPv4 string addresses with no CIDR's. :param object path_to_save_csv_files_in: A string directory path to save files in. """ # Inherit everything from the parent base class: PurpleAirDataLogger - super().__init__(PurpleAirAPIReadKey, PurpleAirAPIWriteKey) + super().__init__( + PurpleAirApiReadKey, PurpleAirApiWriteKey, PurpleAirApiIpv4Address + ) # save off the store path internally for later access self._path_to_save_csv_files_in = path_to_save_csv_files_in @@ -509,8 +517,19 @@ def store_sensor_data(self, single_sensor_data_dict): file_obj = None # Second make an instance our our data logger + ipv4_address_list = [] + if args.paa_local_sensor_request_json_file: + # This is a temp working solution. We will need to redo this at some point. + import json + + file_obj = open(args.paa_local_sensor_request_json_file, "r") + the_json_file = json.load(file_obj) + file_obj.close() + ipv4_address_list = the_json_file["sensor_ip_list"] # LOAD THIS IN MAYBE ??? + del the_json_file + the_paa_csv_data_logger = PurpleAirCSVDataLogger( - args.paa_read_key, args.paa_write_key, args.save_file_path + args.paa_read_key, args.paa_write_key, ipv4_address_list, args.save_file_path ) # Third choose what run method to execute depending on @@ -519,4 +538,5 @@ def store_sensor_data(self, single_sensor_data_dict): args.paa_multiple_sensor_request_json_file, args.paa_single_sensor_request_json_file, args.paa_group_sensor_request_json_file, + args.paa_local_sensor_request_json_file, ) diff --git a/purpleair_data_logger/PurpleAirDataLogger.py b/purpleair_data_logger/PurpleAirDataLogger.py index 06d3374..8238088 100644 --- a/purpleair_data_logger/PurpleAirDataLogger.py +++ b/purpleair_data_logger/PurpleAirDataLogger.py @@ -25,7 +25,8 @@ def generate_common_arg_parser(argparse_description=""): parser.add_argument( "-paa_read_key", - required=True, + required=False, + default=None, dest="paa_read_key", type=str, help="""The PurpleAirAPI Read key""", @@ -33,7 +34,8 @@ def generate_common_arg_parser(argparse_description=""): parser.add_argument( "-paa_write_key", - required=True, + required=False, + default=None, dest="paa_write_key", type=str, help="""The PurpleAirAPI write key""", @@ -72,6 +74,17 @@ def generate_common_arg_parser(argparse_description=""): sensor request.""", ) + parser.add_argument( + "-paa_local_sensor_request_json_file", + required=False, + default=None, + dest="paa_local_sensor_request_json_file", + type=str, + help="""The + path to a json file containing the parameters to send a local + sensor request.""", + ) + return parser @@ -92,16 +105,22 @@ class PurpleAirDataLogger: will only need to define their own 'store_sensor_data' method. """ - def __init__(self, PurpleAirAPIReadKey, PurpleAirAPIWriteKey): + def __init__( + self, + PurpleAirApiReadKey=None, + PurpleAirApiWriteKey=None, + PurpleAirApiIpv4Address=None, + ): """ - :param str PurpleAirAPIReadKey: A valid PurpleAirAPI Read key + :param str PurpleAirApiReadKey: A valid PurpleAirAPI Read key :param object psql_db_conn: A valid PG8000 database connection """ # Make one instance of our PurpleAirAPI class self._purpleair_api_obj = PurpleAirAPI( - your_api_read_key=PurpleAirAPIReadKey, - your_api_write_key=PurpleAirAPIWriteKey, + your_api_read_key=PurpleAirApiReadKey, + your_api_write_key=PurpleAirApiWriteKey, + your_ipv4_address=PurpleAirApiIpv4Address, ) # Define how often we send requests @@ -147,9 +166,9 @@ def store_sensor_data(self, single_sensor_data_dict): "Must be implemented by class that is inheriting PurpleAirDataLogger!" ) - def _validate_sensor_data_before_insert(self, the_modified_sensor_data): + def _validate_sensor_data_before_insert(self, the_modified_sensor_data) -> dict: """ - Before we store the data, we must make sure all fields have been included + Before we store the data, we must make sure all fields have been included. Our psql/sqlite store statements expect all fields regardless of what we request. :param dict the_modified_sensor_data: A single layer dictionary containing a single sensors data. @@ -171,13 +190,16 @@ def _validate_sensor_data_before_insert(self, the_modified_sensor_data): # Then return the modified copy return temp_the_modified_sensor_data - def _run_loop_for_storing_single_sensor_data(self, the_json_file): + def _run_loop_for_storing_single_sensor_data(self, json_config_file) -> dict: """ A method containing the run loop for inserting a single sensors' data into the data logger. :param dict json_config_file: A dictionary object of the json config file using json load. """ + # Set the polling interval + self.send_request_every_x_seconds = json_config_file["poll_interval_seconds"] + while True: print( "_run_loop_for_storing_single_sensor_data - Beep boop I am alive...\n\n" @@ -185,14 +207,14 @@ def _run_loop_for_storing_single_sensor_data(self, the_json_file): # We will request data once every 65 seconds. debug_log( f"""Requesting new data from a sensor with index - {the_json_file['sensor_index']}...""" + {json_config_file['sensor_index']}...""" ) sensor_data = None sensor_data = self._purpleair_api_obj.request_sensor_data( - the_json_file["sensor_index"], - the_json_file["read_key"], - the_json_file["fields"], + json_config_file["sensor_index"], + json_config_file["read_key"], + json_config_file["fields"], ) # Let's make it easier on ourselves by making the sensor data one level deep. @@ -246,7 +268,7 @@ def _run_loop_for_storing_single_sensor_data(self, the_json_file): ) self.store_sensor_data(the_modified_sensor_data) debug_log( - f"""Waiting {self._send_request_every_x_seconds} seconds before + f"""Waiting {self.send_request_every_x_seconds} seconds before requesting new data again...""" ) @@ -256,13 +278,16 @@ def _run_loop_for_storing_single_sensor_data(self, the_json_file): sleep(self.send_request_every_x_seconds) - def _run_loop_for_storing_multiple_sensors_data(self, json_config_file): + def _run_loop_for_storing_multiple_sensors_data(self, json_config_file) -> dict: """ A method containing the run loop for inserting a multiple sensors' data into the data logger. :param dict json_config_file: A dictionary object of the json config file using json load. """ + # Set the polling interval + self.send_request_every_x_seconds = json_config_file["poll_interval_seconds"] + while True: print( "_run_loop_for_storing_multiple_sensors_data - Beep boop I am alive...\n\n" @@ -305,7 +330,7 @@ def _run_loop_for_storing_multiple_sensors_data(self, json_config_file): self.store_sensor_data(store_sensor_data_type) debug_log( - f"""Waiting {self._send_request_every_x_seconds} seconds before + f"""Waiting {self.send_request_every_x_seconds} seconds before requesting new data again...""" ) @@ -315,13 +340,16 @@ def _run_loop_for_storing_multiple_sensors_data(self, json_config_file): sleep(self.send_request_every_x_seconds) - def _run_loop_for_storing_group_sensors_data(self, json_config_file): + def _run_loop_for_storing_group_sensors_data(self, json_config_file) -> dict: """ A method containing the run loop for inserting a group sensors' data into the data logger. :param dict json_config_file: A dictionary object of the json config file using json load. """ + # Set the polling interval + self.send_request_every_x_seconds = json_config_file["poll_interval_seconds"] + group_id_to_use = None while True: print( @@ -430,18 +458,331 @@ def _run_loop_for_storing_group_sensors_data(self, json_config_file): self.store_sensor_data(store_sensor_data_type) debug_log( - f"""Waiting {self._send_request_every_x_seconds} seconds before + f"""Waiting {self.send_request_every_x_seconds} seconds before requesting new data again...""" ) sleep(self.send_request_every_x_seconds) - def _construct_store_sensor_data_type(self, raw_data): + def _run_loop_for_storing_local_sensors_data(self, json_config_file) -> dict: + """ + A method containing the run loop for inserting a local sensors' data into the data logger. + + :param dict json_config_file: A dictionary object of the json config file using json load. + """ + + while True: + print( + "_run_loop_for_storing_local_sensors_data - Beep boop I am alive...\n\n" + ) + + # Ask for our local sensor data + local_sensor_dict = self._purpleair_api_obj.request_local_sensor_data() + + # The data that is returned via an internal network API is different than the data returned via an external network API. + # With that in mind let's try to map internal network API values to external network API values. That way we don't have to + # write more code in the PADL's. + for ip, sensor_dict in local_sensor_dict.items(): + the_modified_sensor_data = {} + + # This timestamp appears to be a unix epoch timestamp (seconds) type. + the_modified_sensor_data["data_time_stamp"] = sensor_dict[ + "response_date" + ] + + # Since we want this to work for all loggers let's make an assumption. The 'SensorId' is the 'name' since it is just a MAC address. + # The 'Id' is not the `sensor_index` it increments when the data changes. It is more of a `sample_id`. Let's just use the mac as a base + # 10 number. That should be unique. + the_modified_sensor_data["sensor_index"] = int(str(sensor_dict["SensorId"]).replace(":", ""), 16) + + ###### Station information and status fields: ###### + the_modified_sensor_data["name"] = sensor_dict["SensorId"] + # "icon": 0, + # "model": "", + the_modified_sensor_data["hardware"] = sensor_dict["hardwarediscovered"] + if sensor_dict["place"] == "inside": + the_modified_sensor_data["location_type"] = 1 + + elif sensor_dict["place"] == "outside": + the_modified_sensor_data["location_type"] = 0 + + # "private": 0, + the_modified_sensor_data["latitude"] = sensor_dict["lat"] + the_modified_sensor_data["longitude"] = sensor_dict["lon"] + # "altitude": 0.0, + # "position_rating": 0, + # "led_brightness": 0, + the_modified_sensor_data["firmware_version"] = sensor_dict["version"] + # "firmware_upgrade": "", + the_modified_sensor_data["rssi"] = sensor_dict["rssi"] + the_modified_sensor_data["uptime"] = sensor_dict["uptime"] + the_modified_sensor_data["pa_latency"] = sensor_dict["latency"] + # "last_seen": 0, + # "last_modified": 0, + # "date_created": 0, + # "channel_state": 0, + # "channel_flags": 0, + # "channel_flags_manual": 0, + # "channel_flags_auto": 0, + # "confidence": 0, + # "confidence_manual": 0, + # "confidence_auto": 0, + + ###### Environmental fields: ###### + if "current_humidity_680" not in sensor_dict.keys(): + the_modified_sensor_data["humidity"] = sensor_dict[ + "current_humidity" + ] + the_modified_sensor_data["humidity_a"] = sensor_dict[ + "current_humidity" + ] + + else: + the_modified_sensor_data["humidity_a"] = sensor_dict[ + "current_humidity" + ] + the_modified_sensor_data["humidity_b"] = sensor_dict[ + "current_humidity_680" + ] + the_modified_sensor_data["humidity"] = float( + ( + sensor_dict["current_humidity"] + + sensor_dict["current_humidity_680"] + ) + / 2 + ) + + if "current_temp_f_680" not in sensor_dict.keys(): + the_modified_sensor_data["temperature"] = sensor_dict[ + "current_temp_f" + ] + the_modified_sensor_data["temperature_a"] = sensor_dict[ + "current_temp_f" + ] + + else: + the_modified_sensor_data["temperature_a"] = sensor_dict[ + "current_temp_f" + ] + the_modified_sensor_data["temperature_b"] = sensor_dict[ + "current_temp_f_680" + ] + the_modified_sensor_data["temperature"] = float( + ( + sensor_dict["current_temp_f"] + + sensor_dict["current_temp_f_680"] + ) + / 2 + ) + + if "pressure_680" not in sensor_dict.keys(): + the_modified_sensor_data["pressure"] = sensor_dict["pressure"] + the_modified_sensor_data["pressure_a"] = sensor_dict["pressure"] + + else: + the_modified_sensor_data["pressure_a"] = sensor_dict["pressure"] + the_modified_sensor_data["pressure_b"] = sensor_dict["pressure_680"] + the_modified_sensor_data["pressure"] = float( + (sensor_dict["pressure"] + sensor_dict["pressure_680"]) / 2 + ) + + ###### Miscellaneous fields: ###### + # "voc": 0.0, + # "voc_a": 0.0, + # "voc_b": 0.0, + # "ozone1": 0.0, + # "analog_input": 0.0, + + ###### PM1.0 fields: ###### + if "p_1_0_um_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm1.0"] = sensor_dict["p_1_0_um"] + the_modified_sensor_data["pm1.0_a"] = sensor_dict["p_1_0_um"] + + else: + the_modified_sensor_data["pm1.0"] = float( + (sensor_dict["p_1_0_um"] + sensor_dict["p_1_0_um_b"]) / 2 + ) + the_modified_sensor_data["pm1.0_a"] = sensor_dict["p_1_0_um"] + the_modified_sensor_data["pm1.0_b"] = sensor_dict["p_1_0_um_b"] + + if "pm1_0_atm_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm1.0_atm"] = sensor_dict["pm1_0_atm"] + the_modified_sensor_data["pm1.0_atm_a"] = sensor_dict["pm1_0_atm"] + + else: + the_modified_sensor_data["pm1.0_atm"] = float( + (sensor_dict["pm1_0_atm"] + sensor_dict["pm1_0_atm_b"]) / 2 + ) + the_modified_sensor_data["pm1.0_atm_a"] = sensor_dict["pm1_0_atm"] + the_modified_sensor_data["pm1.0_atm_b"] = sensor_dict["pm1_0_atm_b"] + + if "pm1_0_cf_1_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm1.0_cf_1"] = sensor_dict["pm1_0_cf_1"] + the_modified_sensor_data["pm1.0_cf_1_a"] = sensor_dict["pm1_0_cf_1"] + + else: + the_modified_sensor_data["pm1.0_cf_1"] = float( + (sensor_dict["pm1_0_cf_1"] + sensor_dict["pm1_0_cf_1_b"]) / 2 + ) + the_modified_sensor_data["pm1.0_cf_1_a"] = sensor_dict["pm1_0_cf_1"] + the_modified_sensor_data["pm1.0_cf_1_b"] = sensor_dict[ + "pm1_0_cf_1_b" + ] + + ###### PM2.5 fields: ###### + # "pm2.5_alt": 0.0, + # "pm2.5_alt_a": 0.0, + # "pm2.5_alt_b": 0.0, + if "p_2_5_um_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm2.5"] = sensor_dict["p_2_5_um"] + the_modified_sensor_data["pm2.5_a"] = sensor_dict["p_2_5_um"] + + else: + the_modified_sensor_data["pm2.5"] = float( + (sensor_dict["p_2_5_um"] + sensor_dict["p_2_5_um_b"]) / 2 + ) + the_modified_sensor_data["pm2.5_a"] = sensor_dict["p_2_5_um"] + the_modified_sensor_data["pm2.5_b"] = sensor_dict["p_2_5_um_b"] + + if "pm2_5_atm_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm2.5_atm"] = sensor_dict["pm2_5_atm"] + the_modified_sensor_data["pm2.5_atm_a"] = sensor_dict["pm2_5_atm"] + + else: + the_modified_sensor_data["pm2.5_atm"] = float( + (sensor_dict["pm2_5_atm"] + sensor_dict["pm2_5_atm_b"]) / 2 + ) + the_modified_sensor_data["pm2.5_atm_a"] = sensor_dict["pm2_5_atm"] + the_modified_sensor_data["pm2.5_atm_b"] = sensor_dict["pm2_5_atm_b"] + + if "pm2_5_cf_1_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm2.5_cf_1"] = sensor_dict["pm2_5_cf_1"] + the_modified_sensor_data["pm2.5_cf_1_a"] = sensor_dict["pm2_5_cf_1"] + + else: + the_modified_sensor_data["pm2.5_cf_1"] = float( + (sensor_dict["pm2_5_cf_1"] + sensor_dict["pm2_5_cf_1_b"]) / 2 + ) + the_modified_sensor_data["pm2.5_cf_1_a"] = sensor_dict["pm2_5_cf_1"] + the_modified_sensor_data["pm2.5_cf_1_b"] = sensor_dict[ + "pm2_5_cf_1_b" + ] + + # # PM2.5 pseudo (simple running) average fields: + # # Note: These are inside the return json as json["sensor"]["stats"]. They are averages of the two sensors. + # # sensor 'a' and sensor 'b'. Each sensors data is inside json["sensor"]["stats_a"] and json["sensor"]["stats_b"] + # "pm2.5_10minute": 0.0, + # "pm2.5_10minute_a": 0.0, + # "pm2.5_10minute_b": 0.0, + # "pm2.5_30minute": 0.0, + # "pm2.5_30minute_a": 0.0, + # "pm2.5_30minute_b": 0.0, + # "pm2.5_60minute": 0.0, + # "pm2.5_60minute_a": 0.0, + # "pm2.5_60minute_b": 0.0, + # "pm2.5_6hour": 0.0, + # "pm2.5_6hour_a": 0.0, + # "pm2.5_6hour_b": 0.0, + # "pm2.5_24hour": 0.0, + # "pm2.5_24hour_a": 0.0, + # "pm2.5_24hour_b": 0.0, + # "pm2.5_1week": 0.0, + # "pm2.5_1week_a": 0.0, + # "pm2.5_1week_b": 0.0, + + ###### PM10.0 fields: ###### + if "p_10_0_um_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm10.0"] = sensor_dict["p_10_0_um"] + the_modified_sensor_data["pm10.0_a"] = sensor_dict["p_10_0_um"] + + else: + the_modified_sensor_data["pm10.0"] = float( + (sensor_dict["p_10_0_um"] + sensor_dict["p_10_0_um_b"]) / 2 + ) + the_modified_sensor_data["pm10.0_a"] = sensor_dict["p_10_0_um"] + the_modified_sensor_data["pm10.0_b"] = sensor_dict["p_10_0_um_b"] + + if "pm10_0_atm_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm10.0_atm"] = sensor_dict["pm10_0_atm"] + the_modified_sensor_data["pm10.0_atm_a"] = sensor_dict["pm10_0_atm"] + + else: + the_modified_sensor_data["pm10.0_atm"] = float( + (sensor_dict["pm10_0_atm"] + sensor_dict["pm10_0_atm_b"]) / 2 + ) + the_modified_sensor_data["pm10.0_atm_a"] = sensor_dict["pm10_0_atm"] + the_modified_sensor_data["pm10.0_atm_b"] = sensor_dict[ + "pm10_0_atm_b" + ] + + if "pm10_0_cf_1_b" not in sensor_dict.keys(): + the_modified_sensor_data["pm10.0_cf_1"] = sensor_dict["pm10_0_cf_1"] + the_modified_sensor_data["pm10.0_cf_1_a"] = sensor_dict[ + "pm10_0_cf_1" + ] + + else: + the_modified_sensor_data["pm10.0_cf_1"] = float( + (sensor_dict["pm10_0_cf_1"] + sensor_dict["pm10_0_cf_1_b"]) / 2 + ) + the_modified_sensor_data["pm10.0_cf_1_a"] = sensor_dict[ + "pm10_0_cf_1" + ] + the_modified_sensor_data["pm10.0_cf_1_b"] = sensor_dict[ + "pm10_0_cf_1_b" + ] + + ###### Particle count fields: ##### + # "0.3_um_count": 0.0, + # "0.3_um_count_a": 0.0, + # "0.3_um_count_b": 0.0, + # "0.5_um_count": 0.0, + # "0.5_um_count_a": 0.0, + # "0.5_um_count_b": 0.0, + # "1.0_um_count": 0.0, + # "1.0_um_count_a": 0.0, + # "1.0_um_count_b": 0.0, + # "2.5_um_count": 0.0, + # "2.5_um_count_a": 0.0, + # "2.5_um_count_b": 0.0, + # "5.0_um_count": 0.0, + # "5.0_um_count_a": 0.0, + # "5.0_um_count_b": 0.0, + # "10.0_um_count": 0.0, + # "10.0_um_count_a": 0.0, + # "10.0_um_count_b": 0.0, + + ###### ThingSpeak fields, used to retrieve data from api.thingspeak.com: ##### + # "primary_id_a": 0, + # "primary_key_a": "", + # "secondary_id_a": 0, + # "secondary_key_a": "", + # "primary_id_b": 0, + # "primary_key_b": "", + # "secondary_id_b": 0, + # "secondary_key_b": "", + + the_modified_sensor_data = self._validate_sensor_data_before_insert( + the_modified_sensor_data + ) + self.store_sensor_data(the_modified_sensor_data) + + debug_log( + f"""Waiting {json_config_file["poll_interval_seconds"]} seconds before + requesting new data again...""" + ) + + del local_sensor_dict + sleep(json_config_file["poll_interval_seconds"]) + + def _construct_store_sensor_data_type(self, raw_data) -> list: """ A method to build the dict data type that the store_sensor_data method expects. :param dict raw_data: The return value from either self._purpleair_api_obj.request_members_data or self._purpleair_api_obj.request_multiple_sensors_data. + + :return A list full of the dict data type that the store_sensor_data method expects. """ # Extract the 'fields' and 'data' parts to make it easier on ourselves @@ -482,7 +823,8 @@ def validate_parameters_and_run( paa_multiple_sensor_request_json_file=None, paa_single_sensor_request_json_file=None, paa_group_sensor_request_json_file=None, - ): + paa_local_sensor_request_json_file=None, + ) -> None: """ A method to choose what run method to execute based on what config file is being used. This shall be considered the main entry point for and PurpleAirDataLogger. @@ -493,14 +835,17 @@ def validate_parameters_and_run( the parameters to send a multiple sensor request(s). :param str paa_group_sensor_request_json_file: The path to a json file containing the parameters to send a group sensor request(s). + :param str paa_local_sensor_request_json_file: The path to a json file containing + the parameters to send a local sensor request(s). """ # Choose what run method to execute depending on - # paa_multiple_sensor_request_json_file/paa_single_sensor_request_json_file/paa_group_sensor_request_json_file + # paa_multiple_sensor_request_json_file/paa_single_sensor_request_json_file/paa_group_sensor_request_json_file/paa_local_sensor_request_json_file if ( paa_multiple_sensor_request_json_file is not None and paa_single_sensor_request_json_file is None and paa_group_sensor_request_json_file is None + and paa_local_sensor_request_json_file is None ): # Now load up that json file file_obj = open(paa_multiple_sensor_request_json_file, "r") @@ -512,6 +857,7 @@ def validate_parameters_and_run( paa_multiple_sensor_request_json_file is None and paa_single_sensor_request_json_file is not None and paa_group_sensor_request_json_file is None + and paa_local_sensor_request_json_file is None ): # Now load up that json file file_obj = open(paa_single_sensor_request_json_file, "r") @@ -523,6 +869,7 @@ def validate_parameters_and_run( paa_multiple_sensor_request_json_file is None and paa_single_sensor_request_json_file is None and paa_group_sensor_request_json_file is not None + and paa_local_sensor_request_json_file is None ): # Now load up that json file file_obj = open(paa_group_sensor_request_json_file, "r") @@ -534,12 +881,25 @@ def validate_parameters_and_run( paa_multiple_sensor_request_json_file is None and paa_single_sensor_request_json_file is None and paa_group_sensor_request_json_file is None + and paa_local_sensor_request_json_file is not None + ): + # Now load up that json file + file_obj = open(paa_local_sensor_request_json_file, "r") + the_json_file = json.load(file_obj) + file_obj.close() + self._run_loop_for_storing_local_sensors_data(the_json_file) + + elif ( + paa_multiple_sensor_request_json_file is None + and paa_single_sensor_request_json_file is None + and paa_group_sensor_request_json_file is None + and paa_local_sensor_request_json_file is None ): raise PurpleAirDataLoggerError( - """Neither '-paa_multiple_sensor_request_json_file' or '-paa_single_sensor_request_json_file' or '-paa_group_sensor_request_json_file' were provided. Please provide at least one!""" + """Neither '-paa_multiple_sensor_request_json_file' or '-paa_single_sensor_request_json_file' or '-paa_group_sensor_request_json_file' or 'and paa_local_sensor_request_json_file is' were provided. Please provide at least one!""" ) else: raise PurpleAirDataLoggerError( - """One parameter '-paa_multiple_sensor_request_json_file' or '-paa_single_sensor_request_json_file' or '-paa_group_sensor_request_json_file' must be provided. Not all!""" + """One parameter '-paa_multiple_sensor_request_json_file' or '-paa_single_sensor_request_json_file' or '-paa_group_sensor_request_json_file' or 'and paa_local_sensor_request_json_file is must be provided. Not all!""" ) diff --git a/sample_json_config_files/sample_group_sensor_request_json_file.json b/sample_json_config_files/sample_group_sensor_request_json_file.json index 1f78311..1259442 100644 --- a/sample_json_config_files/sample_group_sensor_request_json_file.json +++ b/sample_json_config_files/sample_group_sensor_request_json_file.json @@ -7,6 +7,7 @@ 95079, 167897 ], + "poll_interval_seconds": 60, "fields": "name, icon, model, hardware, location_type, private, latitude, longitude, altitude, position_rating, led_brightness, firmware_version, firmware_upgrade, rssi, uptime, pa_latency, memory, last_seen, last_modified, date_created, channel_state, channel_flags, channel_flags_manual, channel_flags_auto, confidence, confidence_manual, confidence_auto,humidity, humidity_a, humidity_b, temperature, temperature_a, temperature_b, pressure, pressure_a, pressure_b,voc, voc_a, voc_b, ozone1, analog_input,pm1.0, pm1.0_a, pm1.0_b, pm1.0_atm, pm1.0_atm_a, pm1.0_atm_b, pm1.0_cf_1, pm1.0_cf_1_a,pm1.0_cf_1_b,pm2.5_alt, pm2.5_alt_a, pm2.5_alt_b, pm2.5, pm2.5_a, pm2.5_b, pm2.5_atm, pm2.5_atm_a, pm2.5_atm_b, pm2.5_cf_1, pm2.5_cf_1_a, pm2.5_cf_1_b,pm2.5_10minute, pm2.5_10minute_a, pm2.5_10minute_b, pm2.5_30minute, pm2.5_30minute_a, pm2.5_30minute_b, pm2.5_60minute, pm2.5_60minute_a, pm2.5_60minute_b, pm2.5_6hour, pm2.5_6hour_a, pm2.5_6hour_b,pm2.5_24hour, pm2.5_24hour_a, pm2.5_24hour_b, pm2.5_1week, pm2.5_1week_a, pm2.5_1week_b,pm10.0, pm10.0_a, pm10.0_b, pm10.0_atm, pm10.0_atm_a, pm10.0_atm_b, pm10.0_cf_1, pm10.0_cf_1_a, pm10.0_cf_1_b,0.3_um_count,0.3_um_count_a,0.3_um_count_b,0.5_um_count,0.5_um_count_a,0.5_um_count_b,1.0_um_count,1.0_um_count_a,1.0_um_count_b,2.5_um_count,2.5_um_count_a,2.5_um_count_b,5.0_um_count,5.0_um_count_a,5.0_um_count_b,10.0_um_count,10.0_um_count_a,10.0_um_count_b,primary_id_a, primary_key_a, secondary_id_a, secondary_key_a, primary_id_b, primary_key_b, secondary_id_b, secondary_key_b", "location_type": null, "read_keys": null, diff --git a/sample_json_config_files/sample_local_sensor_request_json_file.json b/sample_json_config_files/sample_local_sensor_request_json_file.json new file mode 100644 index 0000000..128d480 --- /dev/null +++ b/sample_json_config_files/sample_local_sensor_request_json_file.json @@ -0,0 +1,7 @@ +{ + "sensor_ip_list": [ + "192.168.86.24", + "192.168.86.25" + ], + "poll_interval_seconds": 1 +} \ No newline at end of file diff --git a/sample_json_config_files/sample_multiple_sensor_request_json_file.json b/sample_json_config_files/sample_multiple_sensor_request_json_file.json index 111aafb..88e7237 100644 --- a/sample_json_config_files/sample_multiple_sensor_request_json_file.json +++ b/sample_json_config_files/sample_multiple_sensor_request_json_file.json @@ -1,4 +1,5 @@ { + "poll_interval_seconds": 60, "fields": "name, icon, model, hardware, location_type, private, latitude, longitude, altitude, position_rating, led_brightness, firmware_version, firmware_upgrade, rssi, uptime, pa_latency, memory, last_seen, last_modified, date_created, channel_state, channel_flags, channel_flags_manual, channel_flags_auto, confidence, confidence_manual, confidence_auto,humidity, humidity_a, humidity_b, temperature, temperature_a, temperature_b, pressure, pressure_a, pressure_b,voc, voc_a, voc_b, ozone1, analog_input,pm1.0, pm1.0_a, pm1.0_b, pm1.0_atm, pm1.0_atm_a, pm1.0_atm_b, pm1.0_cf_1, pm1.0_cf_1_a,pm1.0_cf_1_b,pm2.5_alt, pm2.5_alt_a, pm2.5_alt_b, pm2.5, pm2.5_a, pm2.5_b, pm2.5_atm, pm2.5_atm_a, pm2.5_atm_b, pm2.5_cf_1, pm2.5_cf_1_a, pm2.5_cf_1_b,pm2.5_10minute, pm2.5_10minute_a, pm2.5_10minute_b, pm2.5_30minute, pm2.5_30minute_a, pm2.5_30minute_b, pm2.5_60minute, pm2.5_60minute_a, pm2.5_60minute_b, pm2.5_6hour, pm2.5_6hour_a, pm2.5_6hour_b,pm2.5_24hour, pm2.5_24hour_a, pm2.5_24hour_b, pm2.5_1week, pm2.5_1week_a, pm2.5_1week_b,pm10.0, pm10.0_a, pm10.0_b, pm10.0_atm, pm10.0_atm_a, pm10.0_atm_b, pm10.0_cf_1, pm10.0_cf_1_a, pm10.0_cf_1_b,0.3_um_count,0.3_um_count_a,0.3_um_count_b,0.5_um_count,0.5_um_count_a,0.5_um_count_b,1.0_um_count,1.0_um_count_a,1.0_um_count_b,2.5_um_count,2.5_um_count_a,2.5_um_count_b,5.0_um_count,5.0_um_count_a,5.0_um_count_b,10.0_um_count,10.0_um_count_a,10.0_um_count_b,primary_id_a, primary_key_a, secondary_id_a, secondary_key_a, primary_id_b, primary_key_b, secondary_id_b, secondary_key_b", "location_type": null, "read_keys": null, diff --git a/sample_json_config_files/sample_single_sensor_request_json_file.json b/sample_json_config_files/sample_single_sensor_request_json_file.json index 5def0bf..4094225 100644 --- a/sample_json_config_files/sample_single_sensor_request_json_file.json +++ b/sample_json_config_files/sample_single_sensor_request_json_file.json @@ -1,4 +1,5 @@ { + "poll_interval_seconds": 60, "sensor_index": 53, "read_key": null, "fields": null diff --git a/setup.py b/setup.py index 0a54e81..a4ca968 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ def read_file(filename): setup( name="purpleair_data_logger", - version="1.2.1", + version="1.3.0a0", license="MIT", author="Carlos Santos", author_email="dose.lucky.sake@cloak.id", @@ -29,6 +29,6 @@ def read_file(filename): "purple air api", "PurpleAirSQLiteDataLogger", ], - install_requires=["pg8000==1.29.6", "requests", "purpleair_api==1.0.2"], + install_requires=["pg8000==1.30.1", "requests", "purpleair_api==1.1.1"], platforms=["Windows 32/64", "Linux 32/64", "MacOS 32/64"], ) diff --git a/sphinx_docs_build/source/conf.py b/sphinx_docs_build/source/conf.py index ab40bd6..cb74df8 100644 --- a/sphinx_docs_build/source/conf.py +++ b/sphinx_docs_build/source/conf.py @@ -23,7 +23,7 @@ author = "carlkidcrypto" # The full version, including alpha/beta/rc tags -release = "V1.2.1" +release = "V1.3.0a0" # -- General configuration ---------------------------------------------------