apmtools 0.2.47__tar.gz → 0.2.49__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {apmtools-0.2.47 → apmtools-0.2.49}/PKG-INFO +1 -1
  2. {apmtools-0.2.47 → apmtools-0.2.49}/pyproject.toml +1 -1
  3. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/classes.py +21 -40
  4. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/matplotlib_renderer.py +5 -0
  5. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/ui.py +114 -10
  6. apmtools-0.2.49/src/apmtools/units.py +190 -0
  7. apmtools-0.2.47/src/apmtools/units.py +0 -390
  8. {apmtools-0.2.47 → apmtools-0.2.49}/.gitignore +0 -0
  9. {apmtools-0.2.47 → apmtools-0.2.49}/LICENSE +0 -0
  10. {apmtools-0.2.47 → apmtools-0.2.49}/README.md +0 -0
  11. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/__init__.py +0 -0
  12. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/data_processing.py +0 -0
  13. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/functions.py +0 -0
  14. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/legacy.py +0 -0
  15. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/__init__.py +0 -0
  16. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/appearance.py +0 -0
  17. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/color_editor.py +0 -0
  18. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/columns.py +0 -0
  19. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/config.py +0 -0
  20. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/data.py +0 -0
  21. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/elements.py +0 -0
  22. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/export.py +0 -0
  23. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/histogram_multi.py +0 -0
  24. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/multi_axis.py +0 -0
  25. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/multi_y.py +0 -0
  26. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/plotly_renderer.py +0 -0
  27. {apmtools-0.2.47 → apmtools-0.2.49}/src/apmtools/shiny/summary.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: apmtools
3
- Version: 0.2.47
3
+ Version: 0.2.49
4
4
  Summary: A collection of tools for processing air pollution monitoring data
5
5
  Project-URL: Homepage, https://github.com/federlorenz/apmtools
6
6
  Author-email: Federico Lorenzetti <lorenzetti.federico@gmail.com>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "apmtools"
7
- version = "0.2.47"
7
+ version = "0.2.49"
8
8
  authors = [
9
9
  { name="Federico Lorenzetti", email="lorenzetti.federico@gmail.com" },
10
10
  ]
@@ -574,7 +574,7 @@ class Dataset(DictionaryPlus):
574
574
  self.scan_folder(directory=f"{directory}{j}/", levels=levels,
575
575
  level=level+1, monitor=monitor, levels_dict=levels_dict, utc_timezone_shift=utc_timezone_shift, interpolate=interpolate, add_m=add_m)
576
576
 
577
- def save_summary(self, save_csv=True, filename="./", columns={}, merged=True):
577
+ def save_summary(self, save_csv=True, filename="./", all_variables=False, merged=True):
578
578
  types_in = list(set(type(v) for v in self.values()))
579
579
 
580
580
  def match_class(x):
@@ -619,13 +619,9 @@ class Dataset(DictionaryPlus):
619
619
  "start", "end", "length", "datetime","timedelta"]
620
620
  columns2 = list(set(d.meta()).difference(
621
621
  set(["filter", "header", "parameters"])))
622
- if "upas" not in columns.keys():
623
- columns3 = ["pm25"]
624
- else:
625
- columns3 = ["pm25"]+columns["upas"] if columns["upas"] != "all" else ["pm25"]+list(
626
- d.set_attrib("columns"))
627
- columns4 = ["pm25correctedrh",
628
- "pm25correctedrhandgrav", "filterid", "grav_not", "grav"]
622
+ columns3 = ["upas_pm25"] if not all_variables else ["upas_"+i for i in list(d.set_attrib("columns"))]+["upas_pm25"]
623
+ columns4 = ["upas_pm25_RHcorrected",
624
+ "upas_pm25_RHgravcorrected", "upas_filterid", "upas_gravimetric", "upas_gravimetric_blankcorrected"]
629
625
  buffer = StringIO()
630
626
  with buffer as file:
631
627
  df = writer(file, delimiter=",")
@@ -658,15 +654,13 @@ class Dataset(DictionaryPlus):
658
654
  app.append(v.m[m] if v.m[m] != None else "")
659
655
  else:
660
656
  app.append("")
661
- if "upas" not in columns.keys():
662
- app.append(v["PM2_5MC"].iloc[i])
663
- else:
664
- app.append(v["PM2_5MC"].iloc[i])
665
- for col in columns3[1:]:
666
- if col in v.columns:
667
- app.append(v[col].iloc[i])
668
- else:
669
- app.append(None)
657
+
658
+ for col in columns3[:-1]:
659
+ if col[5:] in v.columns:
660
+ app.append(v[col[5:]].iloc[i])
661
+ else:
662
+ app.append(None)
663
+ app.append(v["PM2_5MC"].iloc[i])
670
664
  xx = (a*v["PM2_5MC"].iloc[i])+(b*v["AtmoRH"].iloc[i])+c
671
665
  app.append(xx)
672
666
  if grav != "":
@@ -695,7 +689,7 @@ class Dataset(DictionaryPlus):
695
689
  columns1 = ["identifier", "monitor",
696
690
  "start", "end", "length", "datetime", "timedelta"]
697
691
  columns2 = list(set(d.meta()))
698
- columns3 = ["CO(ppm)"]
692
+ columns3 = ["lascar_CO(ppm)"]
699
693
 
700
694
  buffer = StringIO()
701
695
  with buffer as file:
@@ -743,9 +737,9 @@ class Dataset(DictionaryPlus):
743
737
  columns1 = ["identifier", "monitor",
744
738
  "start", "end", "length", "datetime", "timedelta"]
745
739
  columns2 = list(set(d.meta()))
746
- columns3 = ["sensorName", "deviceId", "resolution",
747
- "PM2.5", "PM10", "CO2", "NO2", "Temperature", "Humidity"]
748
- columns4 = ["pm25correctedrh"]
740
+ columns3 = ["lcm_sensorName", "lcm_deviceId", "lcm_resolution",
741
+ "lcm_PM2.5", "lcm_PM10", "lcm_CO2", "lcm_NO2", "lcm_Temperature", "lcm_Humidity"] if all_variables else ["lcm_PM2.5"]
742
+ columns4 = ["lcm_PM2.5correctedrh"]
749
743
 
750
744
  buffer = StringIO()
751
745
  with buffer as file:
@@ -774,7 +768,7 @@ class Dataset(DictionaryPlus):
774
768
  else:
775
769
  app.append("")
776
770
  for m in columns3:
777
- app.append(v[m].iloc[i])
771
+ app.append(v[m[4:]].iloc[i])
778
772
  xx = (a*v["PM2.5"].iloc[i])+(b*v["Humidity"].iloc[i])+c
779
773
  app.append(xx)
780
774
  df.writerow(list(map(str, app)))
@@ -793,13 +787,8 @@ class Dataset(DictionaryPlus):
793
787
  columns1 = ["identifier", "monitor",
794
788
  "start", "end", "length", "datetime", "timedelta"]
795
789
  columns2 = list(set(d.meta()))
796
- columns3 = ["pm2_5", "pm2_5_adj"]
797
- columns4 = []
798
- if "purple" not in columns.keys():
799
- columns4 = []
800
- else:
801
- columns4 = columns["purple"] if columns["purple"] != "all" else list(
802
- d.set_attrib("columns"))
790
+ columns3 = ["purple_pm25", "purple_pm25_RHcorrected"]
791
+ columns4 = [] if not all_variables else ["purple_"+i for i in list(d.set_attrib("columns"))]
803
792
  buffer = StringIO()
804
793
  with buffer as file:
805
794
  df = writer(file, delimiter=",")
@@ -829,17 +818,9 @@ class Dataset(DictionaryPlus):
829
818
  app.append(
830
819
  ((v["pm2_5_cf_1"]+v["pm2_5_cf_1_b"])/2).iloc[i])
831
820
  app.append(v["pm_adj"].iloc[i])
832
- if "purple" in columns.keys():
833
- if columns["purple"] == "all":
834
- for col in list(d.set_attrib("columns")):
835
- if col in v.columns:
836
- app.append(v[col].iloc[i])
837
- else:
838
- app.append(None)
839
- else:
840
- for col in columns["purple"]:
841
- if col in v.columns:
842
- app.append(v[col].iloc[i])
821
+ for col in columns4:
822
+ if col[6:] in v.columns:
823
+ app.append(v[col[6:]].iloc[i])
843
824
  else:
844
825
  app.append(None)
845
826
  df.writerow(list(map(str, app)))
@@ -738,6 +738,11 @@ def _matplotlib_direct_figure(spec, *, title="", x_label="", y_label="",
738
738
  for group in (group_names or [None]):
739
739
  for variable in variable_names:
740
740
  key = (variable, group)
741
+ # A visible element may be only one of several Y variables
742
+ # within a group. Never create proxy legend entries for
743
+ # combinations with no plotted observations.
744
+ if key not in active:
745
+ continue
741
746
  label = f"{group}, {variable}" if group is not None else variable
742
747
  legend_handles.append(Line2D([], [], color=multi_colors[key], linestyle=multi_dashes[key], linewidth=line_width))
743
748
  legend_labels_out.append(rename.get(label, label))
@@ -479,7 +479,7 @@ if (!window.__apmColorPickerInstalled) {
479
479
  if not np.isfinite(bound):
480
480
  continue
481
481
  mask = values.gt(bound) if comparison == "gt" else values.lt(bound)
482
- current = current.loc[mask.fillna(False)].copy()
482
+ current = current.loc[mask.fillna(False) | values.isna()].copy()
483
483
  values = values.loc[current.index]
484
484
  return current
485
485
 
@@ -499,7 +499,11 @@ if (!window.__apmColorPickerInstalled) {
499
499
 
500
500
  def _label_string(field):
501
501
  # Internal adapter for the existing renderer/export APIs.
502
- keys = _label_keys[field].get()
502
+ # Label discovery is downstream of figure rendering. Do not
503
+ # subscribe the figure to its own discovered key set: this
504
+ # otherwise forms plot -> legend keys -> plot feedback cycles.
505
+ with reactive.isolate():
506
+ keys = _label_keys[field].get()
503
507
  values = _label_values[field].get()
504
508
  return "; ".join(f"{key}={values.get(key, key)}" for key in keys
505
509
  if values.get(key, key) != key)
@@ -532,6 +536,12 @@ if (!window.__apmColorPickerInstalled) {
532
536
  @reactive.effect
533
537
  def _watch():
534
538
  keys = _label_keys[field].get()
539
+ # A plot-type transition unmounts the old inputs asynchronously.
540
+ # Do not consume values from the previous plot's editors while
541
+ # Shiny is replacing their DOM nodes.
542
+ with reactive.isolate():
543
+ if not keys:
544
+ return
535
545
  # Read current mappings without subscribing this watcher to
536
546
  # its own writes: otherwise each keystroke can retrigger it.
537
547
  with reactive.isolate():
@@ -742,6 +752,13 @@ if (!window.__apmColorPickerInstalled) {
742
752
  if not choices:
743
753
  return ui.help_text(f"No compatible X variables for {kind}.")
744
754
  selected = initial_filters.get("x", [])
755
+ # This control is remounted on plot-type changes. Never feed
756
+ # a datetime line X into a categorical box/bar selectize:
757
+ # Shiny otherwise has to reconcile a selection absent from
758
+ # the new choice set while dependent reactive plots run.
759
+ candidate = [selected] if isinstance(selected, str) else list(selected or [])
760
+ candidate = [value for value in candidate if value in choices]
761
+ selected = candidate if multiple else (candidate[0] if candidate else "")
745
762
  if multiple:
746
763
  return ui.input_selectize(
747
764
  "x", "X-axis / variables" if kind in ("scatter", "histogram") else "X-axis / categories",
@@ -788,8 +805,11 @@ if (!window.__apmColorPickerInstalled) {
788
805
  @reactive.event(input.group_by, ignore_none=False)
789
806
  def sync_panel_group_choices():
790
807
  selected = list(input.group_by() or [])
808
+ with reactive.isolate():
809
+ current_panels = list(_optional_input("panel_by", []) or [])
810
+ valid_panels = [name for name in current_panels if name in selected]
791
811
  ui.update_selectize("panel_by", choices={name: name for name in selected},
792
- selected=selected)
812
+ selected=valid_panels)
793
813
 
794
814
  @render.ui
795
815
  def frequency_options():
@@ -800,6 +820,34 @@ if (!window.__apmColorPickerInstalled) {
800
820
  ui.input_checkbox("flooring_timestamp", "Floor timestamps", value=initial_filters.get("flooring_timestamp", True)),
801
821
  )
802
822
 
823
+ # The virtual group choices depend on plot type and selected axes,
824
+ # not on the Group by value. Updating a selectize control while
825
+ # subscribing to that same control can create an invalidation loop,
826
+ # especially during a line -> box/bar transition with multiple Y's.
827
+ _last_axis_group_choices = reactive.value(None)
828
+
829
+ @reactive.effect
830
+ def sync_axis_group_choices():
831
+ kind = input.plot_type()
832
+ x_raw = _optional_input("x", [])
833
+ y_raw = _optional_input("y", [])
834
+ xs = [x_raw] if isinstance(x_raw, str) else list(x_raw or [])
835
+ ys = [y_raw] if isinstance(y_raw, str) else list(y_raw or [])
836
+ choices = list(group_columns)
837
+ if kind in ("histogram", "scatter") and len(xs) > 1:
838
+ choices.append("variables_x")
839
+ if kind != "histogram" and len(ys) > 1:
840
+ choices.append("variables_y")
841
+ signature = tuple(choices)
842
+ with reactive.isolate():
843
+ previous = _last_axis_group_choices.get()
844
+ current = list(_optional_input("group_by", []) or [])
845
+ if signature == previous:
846
+ return
847
+ _last_axis_group_choices.set(signature)
848
+ selected = [g for g in current if g in choices]
849
+ ui.update_selectize("group_by", choices={c: c for c in choices}, selected=selected)
850
+
803
851
  @reactive.calc
804
852
  def selected_data():
805
853
  current = filtered_summary()
@@ -830,7 +878,8 @@ if (!window.__apmColorPickerInstalled) {
830
878
  ):
831
879
  return pd.DataFrame()
832
880
 
833
- selected_groups = list(input.group_by() or [])
881
+ selected_groups = [g for g in (input.group_by() or [])
882
+ if g not in ("variables_x", "variables_y")]
834
883
  # Derive hour/day/etc. through group_stat without aggregation.
835
884
  # The returned index column identifies source rows.
836
885
  for component in selected_groups:
@@ -908,6 +957,7 @@ if (!window.__apmColorPickerInstalled) {
908
957
  y_input = None if selected_plot == "histogram" else input.y()
909
958
  selected_y = ([y_input] if isinstance(y_input, str) else list(y_input or []))
910
959
  selected_groups = list(input.group_by() or [])
960
+ physical_groups = [g for g in selected_groups if g not in ("variables_x", "variables_y")]
911
961
  frequency = FREQUENCIES.get(input.frequency())
912
962
  should_aggregate = AGGREGATES.get(input.aggregate()) is not None
913
963
 
@@ -919,6 +969,13 @@ if (!window.__apmColorPickerInstalled) {
919
969
  selected_plot != "histogram" and not selected_y
920
970
  ):
921
971
  return {"error": "No data for the selected filters"}
972
+ # The X widget is replaced asynchronously by render.ui. Until
973
+ # the browser mounts it, the old line X can remain in input.x.
974
+ # Treat that intermediate state as unready, not as box data.
975
+ if selected_plot in ("box", "bar") and any(
976
+ x not in categorical_columns for x in selected_x
977
+ ):
978
+ return {"error": "Waiting for categorical X-axis selection"}
922
979
 
923
980
  aggregate = AGGREGATES.get(input.aggregate())
924
981
  def mapped(column):
@@ -954,16 +1011,35 @@ if (!window.__apmColorPickerInstalled) {
954
1011
  if selected_plot == "histogram" and len(x_variables) > 1:
955
1012
  from .histogram_multi import histogram_long_data
956
1013
  plot_df = histogram_long_data(plot_df, x_variables, group_columns=[
957
- column_map[c] for c in selected_groups if column_map[c] in plot_df.columns
1014
+ column_map[c] for c in physical_groups if column_map[c] in plot_df.columns
958
1015
  ])
1016
+ plot_df["variables_x"] = plot_df["__hist_variable"]
959
1017
  x_column = "__hist_value"
960
1018
  x_label_override = " | ".join(x_variables)
961
1019
 
1020
+ if (selected_plot == "scatter" and "variables_x" in selected_groups
1021
+ and len(x_variables) > 1):
1022
+ id_columns = [c for c in plot_df.columns if c not in x_variables]
1023
+ plot_df = plot_df.melt(id_vars=id_columns, value_vars=x_variables,
1024
+ var_name="variables_x", value_name="__axis_x_value")
1025
+ x_column = "__axis_x_value"
1026
+ x_variables = [x_column]
1027
+
962
1028
  if selected_plot in ("box", "bar"):
963
1029
  plot_df = plot_df.copy(deep=False)
964
1030
  plot_df["__plot_category"] = _composite_labels(plot_df, x_columns)
965
1031
  x_column = "__plot_category"
966
1032
 
1033
+ if "variables_y" in selected_groups and len(y_columns) > 1:
1034
+ # Make the selected Y variable an actual categorical dimension,
1035
+ # so it works with ordinary grouping and panel partitioning.
1036
+ id_columns = [c for c in plot_df.columns if c not in y_columns]
1037
+ plot_df = plot_df.melt(id_vars=id_columns, value_vars=y_columns,
1038
+ var_name="variables_y", value_name="__axis_y_value")
1039
+ y_columns = ["__axis_y_value"]
1040
+ # The categorical X labels have already been computed above.
1041
+ # Scatter and bar/box now use the standard single-Y renderer.
1042
+
967
1043
  # Convert durations once for Plotly, Matplotlib, editable
968
1044
  # numeric bounds, faceting and exported plots. Retain the
969
1045
  # original variable name and label its displayed unit.
@@ -980,8 +1056,12 @@ if (!window.__apmColorPickerInstalled) {
980
1056
  # Multiple grouping columns are supported by group_stat(). For
981
1057
  # plotting, Plotly needs one color/category column, so combine the
982
1058
  # selected grouping columns into a readable composite label.
983
- group_columns = [column_map[c] for c in selected_groups
1059
+ group_columns = [column_map[c] for c in physical_groups
984
1060
  if column_map[c] in plot_df.columns]
1061
+ if "variables_x" in selected_groups and "variables_x" in plot_df:
1062
+ group_columns.append("variables_x")
1063
+ if "variables_y" in selected_groups and "variables_y" in plot_df:
1064
+ group_columns.append("variables_y")
985
1065
  if group_columns:
986
1066
  plot_df = plot_df.copy(deep=False)
987
1067
  plot_df["__plot_group"] = (
@@ -1317,6 +1397,11 @@ if (!window.__apmColorPickerInstalled) {
1317
1397
  ui.update_text(field, value="")
1318
1398
  for field in ("legend_labels", "x_tick_labels", "y_tick_labels", "panel_titles"):
1319
1399
  _set_label_keys(field, ())
1400
+ # Invalidate figure-derived editor identities immediately. The
1401
+ # previous lineplot legend/ticks must never be treated as boxplot
1402
+ # identities during the asynchronous input transition.
1403
+ rendered_legend_keys.set(())
1404
+ rendered_tick_keys.set(((), ()))
1320
1405
  _color_keys.set(())
1321
1406
  ui.update_select("palette", selected="Default")
1322
1407
  ui.update_select("template", selected="plotly")
@@ -1397,7 +1482,12 @@ if (!window.__apmColorPickerInstalled) {
1397
1482
  from .appearance import _parse_label_map
1398
1483
  with reactive.isolate():
1399
1484
  mapping = _parse_label_map(_label_string("legend_labels"))
1400
- reverse = {v: k for k, v in mapping.items() if v != k}
1485
+ # Resolve displayed labels against stable, original keys. A
1486
+ # reverse dictionary is unsafe: two different keys may have
1487
+ # the same edited label, and mapping order then makes keys
1488
+ # alternate as the figure is rendered repeatedly.
1489
+ with reactive.isolate():
1490
+ known_keys = _label_keys["legend_labels"].get()
1401
1491
  if is_plotly:
1402
1492
  if getattr(fig.layout, "showlegend", None) is False:
1403
1493
  labels = []
@@ -1408,8 +1498,22 @@ if (!window.__apmColorPickerInstalled) {
1408
1498
  legends = list(getattr(fig, "legends", []))
1409
1499
  legends += [ax.get_legend() for ax in fig.axes if ax.get_legend() is not None]
1410
1500
  labels = [txt.get_text() for leg in legends for txt in leg.get_texts()]
1411
- keys = tuple(dict.fromkeys(reverse.get(label, label) for label in labels
1412
- if label.strip() and label not in ("Y variable", "Grouping", "Legend", "All observations")))
1501
+ excluded = ("Y variable", "Grouping", "Legend", "All observations")
1502
+ labels = [label for label in labels if label.strip() and label not in excluded]
1503
+ # If this is merely a relabelled rendering of the existing
1504
+ # traces, do not rediscover/rename their identities.
1505
+ expected = [mapping.get(key, key) for key in known_keys]
1506
+ if known_keys and set(labels) == set(expected):
1507
+ keys = tuple(known_keys)
1508
+ else:
1509
+ reverse = {}
1510
+ for key in known_keys:
1511
+ display = mapping.get(key, key)
1512
+ reverse.setdefault(display, []).append(key)
1513
+ keys = tuple(dict.fromkeys(
1514
+ reverse[label][0] if len(reverse.get(label, ())) == 1
1515
+ else label for label in labels
1516
+ ))
1413
1517
  with reactive.isolate():
1414
1518
  old = rendered_legend_keys.get()
1415
1519
  if keys != old:
@@ -1847,7 +1951,7 @@ if (!window.__apmColorPickerInstalled) {
1847
1951
  if not np.isfinite(bound):
1848
1952
  continue
1849
1953
  mask = values.gt(bound) if suffix == "gt" else values.lt(bound)
1850
- current = current.loc[mask.fillna(False)].copy()
1954
+ current = current.loc[mask.fillna(False) | values.isna()].copy()
1851
1955
  values = values.loc[current.index]
1852
1956
  if current.empty:
1853
1957
  return current
@@ -0,0 +1,190 @@
1
+ upas_units = {'upas_AccelComplianceCnt': '#',
2
+ 'upas_AccelComplianceHrs': 'hrs',
3
+ 'upas_AccelT': '°C',
4
+ 'upas_AccelX': 'mg',
5
+ 'upas_AccelXMax': 'mg',
6
+ 'upas_AccelXMin': 'mg',
7
+ 'upas_AccelXVar': 'mg',
8
+ 'upas_AccelY': 'mg',
9
+ 'upas_AccelYMax': 'mg',
10
+ 'upas_AccelYMin': 'mg',
11
+ 'upas_AccelYVar': 'mg',
12
+ 'upas_AccelZ': 'mg',
13
+ 'upas_AccelZMax': 'mg',
14
+ 'upas_AccelZMin': 'mg',
15
+ 'upas_AccelZVar': 'mg',
16
+ 'upas_AtmoAlt': 'm',
17
+ 'upas_AtmoDensity': 'g L-1',
18
+ 'upas_AtmoP': 'hPa',
19
+ 'upas_AtmoRH': '%',
20
+ 'upas_AtmoT': '°C',
21
+ 'upas_BCS1': 'bool',
22
+ 'upas_BCS2': 'bool',
23
+ 'upas_BC_NPG': 'bool',
24
+ 'upas_BFGenergy': 'integer',
25
+ 'upas_BattVolt': 'V',
26
+ 'upas_BatteryCharge': '%',
27
+ 'upas_CO2': 'ppm',
28
+ 'upas_Charging': 'bool',
29
+ 'upas_DateTimeUTC': 'HH:MM:SS',
30
+ 'upas_Dead': 'bool',
31
+ 'upas_ExtPow': '-',
32
+ 'upas_FLOWCTL': 's',
33
+ 'upas_FdpT': '°C',
34
+ 'upas_FilterDP': 'Pa',
35
+ 'upas_GPSQual': '-',
36
+ 'upas_GPSRT': 's',
37
+ 'upas_GPSalt': 'm',
38
+ 'upas_GPShDOP': '-',
39
+ 'upas_GPSlat': 'decimalDegree',
40
+ 'upas_GPSlon': 'decimalDegree',
41
+ 'upas_GPSsat': '#',
42
+ 'upas_GPSspeed': 'm s-1',
43
+ 'upas_HighVisRaw': '-',
44
+ 'upas_IRRaw': '-',
45
+ 'upas_LUX': 'lux',
46
+ 'upas_LowVisRaw': '-',
47
+ 'upas_MFSVout': 'V',
48
+ 'upas_MassFlow': 'g min-1',
49
+ 'upas_MassFlowFactory': 'g min-1',
50
+ 'upas_NOXRaw': '-',
51
+ 'upas_OverallFlowFactory': 'L min-1',
52
+ 'upas_OverallFlowOffset': 'L min-1',
53
+ 'upas_OverallFlowRate': 'L min-1)',
54
+ 'upas_PCB1T': '°C',
55
+ 'upas_PCB2P': 'hPa',
56
+ 'upas_PCB2T': '°C',
57
+ 'upas_PM0_5NC': '# cm-3',
58
+ 'upas_PM0_5NCVar': '# cm-3',
59
+ 'upas_PM10MC': 'µg m-3',
60
+ 'upas_PM10MCVar': 'µg m-3',
61
+ 'upas_PM10NC': '# cm-3',
62
+ 'upas_PM10NCVar': '# cm-3',
63
+ 'upas_PM1MC': 'µg m-3',
64
+ 'upas_PM1MCVar': 'µg m-3',
65
+ 'upas_PM1NC': '# cm-3',
66
+ 'upas_PM1NCVar': '# cm-3',
67
+ 'upas_PM2_5MC': 'μg/m3',
68
+ 'upas_PM2_5MCVar': 'µg m-3',
69
+ 'upas_PM2_5NC': '# cm-3',
70
+ 'upas_PM2_5NCVar': '# cm-3',
71
+ 'upas_PM2_5SampledMass': 'µg',
72
+ 'upas_PM2_5SampledMassFactory': 'μg',
73
+ 'upas_PM2_5SampledMassOffset': 'μg',
74
+ 'upas_PM4MC': 'µg m-3',
75
+ 'upas_PM4MCVar': 'µg m-3',
76
+ 'upas_PM4NC': '# cm-3',
77
+ 'upas_PM4NCVar': '# cm-3',
78
+ 'upas_PMFanErrorCnt': '#',
79
+ 'upas_PMFanSpeedWarn': '#',
80
+ 'upas_PMLaserErrorCnt': '#',
81
+ 'upas_PMMeasCnt': '#',
82
+ 'upas_PMReadingErrorCnt': '#',
83
+ 'upas_PMtypicalParticleSize': 'µm',
84
+ 'upas_PMtypicalParticleSizeVar': 'µm',
85
+ 'upas_PT100R': 'Ω',
86
+ 'upas_PumpPow1': 'integer',
87
+ 'upas_PumpPow2': 'integer',
88
+ 'upas_PumpV': 'V',
89
+ 'upas_PumpingFlowFactory': 'L min-1',
90
+ 'upas_PumpingFlowOffset': 'L min-1',
91
+ 'upas_PumpingFlowRate': 'L min-1)',
92
+ 'upas_PumpsON': 'bool',
93
+ 'upas_RotX': 'mdeg s-1',
94
+ 'upas_RotXMax': 'mdeg s-1',
95
+ 'upas_RotXMin': 'mdeg s-1',
96
+ 'upas_RotXVar': 'mdeg s-1',
97
+ 'upas_RotY': 'mdeg s-1',
98
+ 'upas_RotYMax': 'mdeg s-1',
99
+ 'upas_RotYMin': 'mdeg s-1',
100
+ 'upas_RotYVar': 'mdeg s-1',
101
+ 'upas_RotZ': 'mdeg s-1',
102
+ 'upas_RotZMax': 'mdeg s-1',
103
+ 'upas_RotZMin': 'mdeg s-1',
104
+ 'upas_RotZVar': 'mdeg s-1',
105
+ 'upas_SCDRH': '%',
106
+ 'upas_SCDT': '°C',
107
+ 'upas_SD_DATAW': 's',
108
+ 'upas_SD_HEADW': 's',
109
+ 'upas_SampleTime': '',
110
+ 'upas_SampledVolume': 'L',
111
+ 'upas_SampledVolumeFactory': 'L',
112
+ 'upas_SampledVolumeOffset': 'L',
113
+ 'upas_StepCount': '#',
114
+ 'upas_TPumpsOFF': 's',
115
+ 'upas_TPumpsON': 's',
116
+ 'upas_U12T': '°C',
117
+ 'upas_U29P': '°C',
118
+ 'upas_U29T': '°C',
119
+ 'upas_UVRaw': '-',
120
+ 'upas_UVindex': '-',
121
+ 'upas_UnixTime': 's',
122
+ 'upas_VOCRaw': '-',
123
+ 'upas_XDown': '%',
124
+ 'upas_Xup': '%',
125
+ 'upas_Ydown': '%',
126
+ 'upas_Yup': '%',
127
+ 'upas_Zdown': '%',
128
+ 'upas_Zup': '%',
129
+ 'upas_cartridgeid': '-',
130
+ 'end': 'YYYY-MM-DDTHH:MM:SS',
131
+ 'index': '-',
132
+ 'length': 'days HH:MM:SS',
133
+ 'upas_pm25': 'µg m-3',
134
+ 'upas_pm25_RHcorrected': 'µg m-3',
135
+ "upas_filterid":"-",
136
+ "upas_gravimetric": "µg m-3",
137
+ "upas_gravimetric_blankcorrected": "µg m-3",
138
+ 'start': 'YYYY-MM-DDTHH:MM:SS',
139
+ 'time': 'YYYY-MM-DDTHH:MM:SS',
140
+ 'upas_upasid': '-',
141
+ 'upas_v3_3': 'V',
142
+ 'upas_v5': 'V'}
143
+
144
+ lascar_units = {"lascar_CO(ppm)":"ppm"}
145
+
146
+
147
+ lcm_units = {"lcm_sensorName": "-", "lcm_deviceId": "-", "lcm_resolution": "-", "lcm_PM2.5": "µg m-3","lcm_PM10": "µg m-3", "lcm_CO2": "ppm", "lcm_NO2": "ppm", "lcm_Temperature": "°C", "lcm_Humidity": "%", "lcm_PM2.5correctedrh": "µg m-3"}
148
+
149
+ purple_units = {'purple_mac_address': '-',
150
+ 'purple_firmware_ver': '-',
151
+ 'purple_hardware': '-',
152
+ 'purple_current_temp_f': 'F',
153
+ 'purple_current_humidity': '%',
154
+ 'purple_current_dewpoint_f': 'F',
155
+ 'purple_pressure': 'mBar',
156
+ 'purple_adc': '',
157
+ 'purple_mem': '',
158
+ 'purple_rssi': '',
159
+ 'purple_uptime': '',
160
+ 'purple_pm1_0_cf_1': 'μg m-3',
161
+ 'purple_pm2_5_cf_1': 'μg m-3',
162
+ 'purple_pm10_0_cf_1': 'μg m-3',
163
+ 'purple_pm1_0_atm': 'μg m-3',
164
+ 'purple_pm2_5_atm': 'μg m-3',
165
+ 'purple_pm10_0_atm': 'μg m-3',
166
+ 'purple_pm2.5_aqi_cf_1': 'μg m-3',
167
+ 'purple_pm2.5_aqi_atm': 'μg m-3',
168
+ 'purple_p_0_3_um': '#',
169
+ 'purple_p_0_5_um': '#',
170
+ 'purple_p_1_0_um': '#',
171
+ 'purple_p_2_5_um': '#',
172
+ 'purple_p_5_0_um': '#',
173
+ 'purple_p_10_0_um': '#',
174
+ 'purple_pm1_0_cf_1_b': 'μg m-3',
175
+ 'purple_pm2_5_cf_1_b': 'μg m-3',
176
+ 'purple_pm10_0_cf_1_b': 'μg m-3',
177
+ 'purple_pm1_0_atm_b': 'μg m-3',
178
+ 'purple_pm2_5_atm_b': 'μg m-3',
179
+ 'purple_pm10_0_atm_b': 'μg m-3',
180
+ 'purple_pm2.5_aqi_cf_1_b': 'μg m-3',
181
+ 'purple_pm2.5_aqi_atm_b': 'μg m-3',
182
+ 'purple_p_0_3_um_b': '#',
183
+ 'purple_p_0_5_um_b': '#',
184
+ 'purple_p_1_0_um_b': '#',
185
+ 'purple_p_2_5_um_b': '#',
186
+ 'purple_p_5_0_um_b': '#',
187
+ 'purple_p_10_0_um_b': '#',
188
+ 'purple_gas': '',
189
+ 'purple_pm25': 'μg m-3',
190
+ "purple_pm25_RHcorrected": "μg m-3"}
@@ -1,390 +0,0 @@
1
- upas_units = {'AccelComplianceCnt': '#',
2
- 'AccelComplianceHrs': 'hrs',
3
- 'AccelT': '°C',
4
- 'AccelX': 'mg',
5
- 'AccelXMax': 'mg',
6
- 'AccelXMin': 'mg',
7
- 'AccelXVar': 'mg',
8
- 'AccelY': 'mg',
9
- 'AccelYMax': 'mg',
10
- 'AccelYMin': 'mg',
11
- 'AccelYVar': 'mg',
12
- 'AccelZ': 'mg',
13
- 'AccelZMax': 'mg',
14
- 'AccelZMin': 'mg',
15
- 'AccelZVar': 'mg',
16
- 'AtmoAlt': 'm',
17
- 'AtmoDensity': 'g L-1',
18
- 'AtmoP': 'hPa',
19
- 'AtmoRH': '%',
20
- 'AtmoT': '°C',
21
- 'BCS1': 'bool',
22
- 'BCS2': 'bool',
23
- 'BC_NPG': 'bool',
24
- 'BFGenergy': 'integer',
25
- 'BattVolt': 'V',
26
- 'BatteryCharge': '%',
27
- 'CO2': 'ppm',
28
- 'Charging': 'bool',
29
- 'DateTimeUTC': 'HH:MM:SS',
30
- 'Dead': 'bool',
31
- 'ExtPow': '-',
32
- 'FLOWCTL': 's',
33
- 'FdpT': '°C',
34
- 'FilterDP': 'Pa',
35
- 'GPSQual': '-',
36
- 'GPSRT': 's',
37
- 'GPSalt': 'm',
38
- 'GPShDOP': '-',
39
- 'GPSlat': 'decimalDegree',
40
- 'GPSlon': 'decimalDegree',
41
- 'GPSsat': '#',
42
- 'GPSspeed': 'm s-1',
43
- 'HighVisRaw': '-',
44
- 'IRRaw': '-',
45
- 'LUX': 'lux',
46
- 'LowVisRaw': '-',
47
- 'MFSVout': 'V',
48
- 'MassFlow': 'g min-1',
49
- 'MassFlowFactory': 'g min-1',
50
- 'NOXRaw': '-',
51
- 'OverallFlowFactory': 'L min-1',
52
- 'OverallFlowOffset': 'L min-1',
53
- 'OverallFlowRate': 'L min-1)',
54
- 'PCB1T': '°C',
55
- 'PCB2P': 'hPa',
56
- 'PCB2T': '°C',
57
- 'PM0_5NC': '# cm-3',
58
- 'PM0_5NCVar': '# cm-3',
59
- 'PM10MC': 'µg m-3',
60
- 'PM10MCVar': 'µg m-3',
61
- 'PM10NC': '# cm-3',
62
- 'PM10NCVar': '# cm-3',
63
- 'PM1MC': 'µg m-3',
64
- 'PM1MCVar': 'µg m-3',
65
- 'PM1NC': '# cm-3',
66
- 'PM1NCVar': '# cm-3',
67
- 'PM2_5MC': 'μg/m3',
68
- 'PM2_5MCVar': 'µg m-3',
69
- 'PM2_5NC': '# cm-3',
70
- 'PM2_5NCVar': '# cm-3',
71
- 'PM2_5SampledMass': 'µg',
72
- 'PM2_5SampledMassFactory': 'μg',
73
- 'PM2_5SampledMassOffset': 'μg',
74
- 'PM4MC': 'µg m-3',
75
- 'PM4MCVar': 'µg m-3',
76
- 'PM4NC': '# cm-3',
77
- 'PM4NCVar': '# cm-3',
78
- 'PMFanErrorCnt': '#',
79
- 'PMFanSpeedWarn': '#',
80
- 'PMLaserErrorCnt': '#',
81
- 'PMMeasCnt': '#',
82
- 'PMReadingErrorCnt': '#',
83
- 'PMtypicalParticleSize': 'µm',
84
- 'PMtypicalParticleSizeVar': 'µm',
85
- 'PT100R': 'Ω',
86
- 'PumpPow1': 'integer',
87
- 'PumpPow2': 'integer',
88
- 'PumpV': 'V',
89
- 'PumpingFlowFactory': 'L min-1',
90
- 'PumpingFlowOffset': 'L min-1',
91
- 'PumpingFlowRate': 'L min-1)',
92
- 'PumpsON': 'bool',
93
- 'RotX': 'mdeg s-1',
94
- 'RotXMax': 'mdeg s-1',
95
- 'RotXMin': 'mdeg s-1',
96
- 'RotXVar': 'mdeg s-1',
97
- 'RotY': 'mdeg s-1',
98
- 'RotYMax': 'mdeg s-1',
99
- 'RotYMin': 'mdeg s-1',
100
- 'RotYVar': 'mdeg s-1',
101
- 'RotZ': 'mdeg s-1',
102
- 'RotZMax': 'mdeg s-1',
103
- 'RotZMin': 'mdeg s-1',
104
- 'RotZVar': 'mdeg s-1',
105
- 'SCDRH': '%',
106
- 'SCDT': '°C',
107
- 'SD_DATAW': 's',
108
- 'SD_HEADW': 's',
109
- 'SampleTime': '',
110
- 'SampledVolume': 'L',
111
- 'SampledVolumeFactory': 'L',
112
- 'SampledVolumeOffset': 'L',
113
- 'StepCount': '#',
114
- 'TPumpsOFF': 's',
115
- 'TPumpsON': 's',
116
- 'U12T': '°C',
117
- 'U29P': '°C',
118
- 'U29T': '°C',
119
- 'UVRaw': '-',
120
- 'UVindex': '-',
121
- 'UnixTime': 's',
122
- 'VOCRaw': '-',
123
- 'XDown': '%',
124
- 'Xup': '%',
125
- 'Ydown': '%',
126
- 'Yup': '%',
127
- 'Zdown': '%',
128
- 'Zup': '%',
129
- 'cartridgeid': '-',
130
- 'end': 'YYYY-MM-DDTHH:MM:SS',
131
- 'index': '-',
132
- 'length': 'days HH:MM:SS',
133
- 'pm25': 'µg m-3',
134
- 'pm25correctedrh': 'µg m-3',
135
- 'start': 'YYYY-MM-DDTHH:MM:SS',
136
- 'time': 'YYYY-MM-DDTHH:MM:SS',
137
- 'upasid': '-',
138
- 'v3_3': 'V',
139
- 'v5': 'V'}
140
-
141
- upas_datatype = {'AccelComplianceCnt': 'integer',
142
- 'AccelComplianceHrs': 'timedelta',
143
- 'AccelT': 'numeric',
144
- 'AccelX': 'numeric',
145
- 'AccelXMax': 'numeric',
146
- 'AccelXMin': 'numeric',
147
- 'AccelXVar': 'numeric',
148
- 'AccelY': 'numeric',
149
- 'AccelYMax': 'numeric',
150
- 'AccelYMin': 'numeric',
151
- 'AccelYVar': 'numeric',
152
- 'AccelZ': 'numeric',
153
- 'AccelZMax': 'numeric',
154
- 'AccelZMin': 'numeric',
155
- 'AccelZVar': 'numeric',
156
- 'AtmoAlt': 'numeric',
157
- 'AtmoDensity': 'numeric',
158
- 'AtmoP': 'numeric',
159
- 'AtmoRH': 'numeric',
160
- 'AtmoT': 'numeric',
161
- 'BCS1': 'bool',
162
- 'BCS2': 'bool',
163
- 'BC_NPG': 'bool',
164
- 'BFGenergy': 'integer',
165
- 'BattVolt': 'numeric',
166
- 'BatteryCharge': '%',
167
- 'CO2': 'numeric',
168
- 'Charging': 'bool',
169
- 'DateTimeUTC': 'datetime',
170
- 'Dead': 'bool',
171
- 'ExtPow': 'bool',
172
- 'FLOWCTL': 'timedelta',
173
- 'FdpT': 'numeric',
174
- 'FilterDP': 'numeric',
175
- 'GPSQual': 'text',
176
- 'GPSRT': 'timedelta',
177
- 'GPSalt': 'numeric',
178
- 'GPShDOP': '',
179
- 'GPSlat': 'numeric',
180
- 'GPSlon': 'numeric',
181
- 'GPSsat': 'integer',
182
- 'GPSspeed': 'numeric',
183
- 'HighVisRaw': '',
184
- 'IRRaw': '',
185
- 'LUX': 'numeric',
186
- 'LowVisRaw': '',
187
- 'MFSVout': 'numeric',
188
- 'MassFlow': 'numeric',
189
- 'MassFlowFactory': 'numeric',
190
- 'NOXRaw': 'numeric',
191
- 'OverallFlowFactory': 'numeric',
192
- 'OverallFlowOffset': 'numeric',
193
- 'OverallFlowRate': 'numeric',
194
- 'PCB1T': 'numeric',
195
- 'PCB2P': 'numeric',
196
- 'PCB2T': 'numeric',
197
- 'PM0_5NC': 'integer',
198
- 'PM0_5NCVar': 'numeric',
199
- 'PM10MC': 'numeric',
200
- 'PM10MCVar': 'numeric',
201
- 'PM10NC': 'numeric',
202
- 'PM10NCVar': 'numeric',
203
- 'PM1MC': 'numeric',
204
- 'PM1MCVar': 'numeric',
205
- 'PM1NC': 'numeric',
206
- 'PM1NCVar': 'numeric',
207
- 'PM2_5MC': 'numeric',
208
- 'PM2_5MCVar': 'numeric',
209
- 'PM2_5NC': 'numeric',
210
- 'PM2_5NCVar': 'numeric',
211
- 'PM2_5SampledMass': 'numeric',
212
- 'PM2_5SampledMassFactory': 'numeric',
213
- 'PM2_5SampledMassOffset': 'numeric',
214
- 'PM4MC': 'numeric',
215
- 'PM4MCVar': 'numeric',
216
- 'PM4NC': 'numeric',
217
- 'PM4NCVar': 'numeric',
218
- 'PMFanErrorCnt': 'numeric',
219
- 'PMFanSpeedWarn': 'bool',
220
- 'PMLaserErrorCnt': 'numeric',
221
- 'PMMeasCnt': 'numeric',
222
- 'PMReadingErrorCnt': 'numeric',
223
- 'PMtypicalParticleSize': 'numeric',
224
- 'PMtypicalParticleSizeVar': 'numeric',
225
- 'PT100R': 'numeric',
226
- 'PumpPow1': 'numeric',
227
- 'PumpPow2': 'numeric',
228
- 'PumpV': 'numeric',
229
- 'PumpingFlowFactory': 'numeric',
230
- 'PumpingFlowOffset': 'numeric',
231
- 'PumpingFlowRate': 'numeric',
232
- 'PumpsON': 'bool',
233
- 'RotX': 'numeric',
234
- 'RotXMax': 'numeric',
235
- 'RotXMin': 'numeric',
236
- 'RotXVar': 'numeric',
237
- 'RotY': 'numeric',
238
- 'RotYMax': 'numeric',
239
- 'RotYMin': 'numeric',
240
- 'RotYVar': 'numeric',
241
- 'RotZ': 'numeric',
242
- 'RotZMax': 'numeric',
243
- 'RotZMin': 'numeric',
244
- 'RotZVar': 'numeric',
245
- 'SCDRH': 'numeric',
246
- 'SCDT': 'numeric',
247
- 'SD_DATAW': 'timedelta',
248
- 'SD_HEADW': 'timedelta',
249
- 'SampleTime': 'datetime',
250
- 'SampledVolume': 'numeric',
251
- 'SampledVolumeFactory': 'numeric',
252
- 'SampledVolumeOffset': 'numeric',
253
- 'StepCount': 'numeric',
254
- 'TPumpsOFF': 'bool',
255
- 'TPumpsON': 'bool',
256
- 'U12T': 'numeric',
257
- 'U29P': 'numeric',
258
- 'U29T': 'numeric',
259
- 'UVRaw': 'numeric',
260
- 'UVindex': 'numeric',
261
- 'UnixTime': 'datetime',
262
- 'VOCRaw': 'numeric',
263
- 'XDown': 'numeric',
264
- 'Xup': 'numeric',
265
- 'Ydown': 'numeric',
266
- 'Yup': 'numeric',
267
- 'Zdown': 'numeric',
268
- 'Zup': 'numeric',
269
- 'end': 'datetime',
270
- 'length': 'timedelta',
271
- 'pm25': 'numeric',
272
- 'pm25correctedrh': 'numeric',
273
- 'start': 'datetime',
274
- 'time': 'datetime',
275
- 'v3_3': 'numeric',
276
- 'v5': 'numeric'}
277
-
278
- lascar_units = {"CO(ppm)":"ppm"}
279
-
280
-
281
- lcm_units = {"sensorName": "-", "deviceId": "-", "resolution": "-", "PM2.5": "µg m-3",
282
- "PM10": "µg m-3", "CO2": "ppm", "NO2": "ppm", "Temperature": "°C", "Humidity": "%"}
283
-
284
- lascar_datatype = {"CO(ppm)": "numeric",
285
- 'start': "datetime",
286
- 'end': "datetime",
287
- 'length': "timedelta",
288
- 'time': "datetime"}
289
-
290
- purple_units = {'mac_address':"-",
291
- 'firmware_ver':"-",
292
- 'hardware':"-",
293
- 'current_temp_f':"F",
294
- 'current_humidity':"%",
295
- 'current_dewpoint_f':"F",
296
- 'pressure':"mBar",
297
- 'adc':"",
298
- 'mem':"",
299
- 'rssi':"",
300
- 'uptime':"",
301
- 'pm1_0_cf_1': "μg m-3",
302
- 'pm2_5_cf_1': "μg m-3",
303
- 'pm10_0_cf_1': "μg m-3",
304
- 'pm1_0_atm': "μg m-3",
305
- 'pm2_5_atm': "μg m-3",
306
- 'pm10_0_atm': "μg m-3",
307
- 'pm2.5_aqi_cf_1': "μg m-3",
308
- 'pm2.5_aqi_atm': "μg m-3",
309
- 'p_0_3_um':"#",
310
- 'p_0_5_um':"#",
311
- 'p_1_0_um':"#",
312
- 'p_2_5_um':"#",
313
- 'p_5_0_um':"#",
314
- 'p_10_0_um':"#",
315
- 'pm1_0_cf_1_b': "μg m-3",
316
- 'pm2_5_cf_1_b': "μg m-3",
317
- 'pm10_0_cf_1_b': "μg m-3",
318
- 'pm1_0_atm_b': "μg m-3",
319
- 'pm2_5_atm_b': "μg m-3",
320
- 'pm10_0_atm_b': "μg m-3",
321
- 'pm2.5_aqi_cf_1_b': "μg m-3",
322
- 'pm2.5_aqi_atm_b': "μg m-3",
323
- 'p_0_3_um_b':"#",
324
- 'p_0_5_um_b':"#",
325
- 'p_1_0_um_b':"#",
326
- 'p_2_5_um_b':"#",
327
- 'p_5_0_um_b':"#",
328
- 'p_10_0_um_b':"#",
329
- 'gas':"",
330
- 'pm_adj': "μg m-3"}
331
-
332
- purple_datatype = {'mac_address': "text",
333
- 'firmware_ver': "text",
334
- 'hardware': "text",
335
- 'current_temp_f': "numeric",
336
- 'current_humidity': "numeric",
337
- 'current_dewpoint_f': "numeric",
338
- 'pressure': "numeric",
339
- 'adc': "text",
340
- 'mem': "text",
341
- 'rssi': "text",
342
- 'uptime': "text",
343
- 'pm1_0_c': "numeric",
344
- 'PumpingFlowFactory': 'numeric',
345
- 'PumpingFlowOffset': 'numeric',
346
- 'PumpingFlowRate': 'numeric',
347
- 'PumpsON': 'bool',
348
- 'RotX': 'numeric',
349
- 'RotXMax': 'numeric',
350
- 'RotXMin': 'numeric',
351
- 'RotXVar': 'numeric',
352
- 'RotY': 'numeric',
353
- 'RotYMax': 'numeric',
354
- 'RotYMin': 'numeric',
355
- 'RotYVar': 'numeric',
356
- 'RotZ': 'numeric',
357
- 'pm1_0_cf_1': "numeric",
358
- 'pm2_5_cf_1': "numeric",
359
- 'pm10_0_cf_1': "numeric",
360
- 'pm1_0_atm': "numeric",
361
- 'pm2_5_atm': "numeric",
362
- 'pm10_0_atm': "numeric",
363
- 'pm2.5_aqi_cf_1': "numeric",
364
- 'pm2.5_aqi_atm': "numeric",
365
- 'p_0_3_um': "numeric",
366
- 'p_0_5_um': "numeric",
367
- 'p_1_0_um': "numeric",
368
- 'p_2_5_um': "numeric",
369
- 'p_5_0_um': "numeric",
370
- 'p_10_0_um': "numeric",
371
- 'pm1_0_cf_1_b': "numeric",
372
- 'pm2_5_cf_1_b': "numeric",
373
- 'pm10_0_cf_1_b': "numeric",
374
- 'pm1_0_atm_b': "numeric",
375
- 'pm2_5_atm_b': "numeric",
376
- 'pm10_0_atm_b': "numeric",
377
- 'pm2.5_aqi_cf_1_b': "numeric",
378
- 'pm2.5_aqi_atm_b': "numeric",
379
- 'p_0_3_um_b': "numeric",
380
- 'p_0_5_um_b': "numeric",
381
- 'p_1_0_um_b': "numeric",
382
- 'p_2_5_um_b': "numeric",
383
- 'p_5_0_um_b': "numeric",
384
- 'p_10_0_um_b': "numeric",
385
- 'gas': "text",
386
- 'pm_adj': "numeric",
387
- 'start':"datetime",
388
- 'end':"datetime",
389
- 'length':"timedelta",
390
- 'time':"datetime"}
File without changes
File without changes
File without changes