gea-program 0.1.0__tar.gz → 0.2.0__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.
- {gea_program-0.1.0/gea_program.egg-info → gea_program-0.2.0}/PKG-INFO +68 -17
- {gea_program-0.1.0 → gea_program-0.2.0}/README.md +57 -16
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/BENCH_TEST_PROTOCOL.md +2 -3
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/__init__.py +7 -5
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/__main__.py +55 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/acceptance_tests.py +205 -42
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/bench.py +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/blind_harness.py +5 -5
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/case_study.py +13 -14
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +2 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +2 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +2 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/client_reports.py +7 -5
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/correlation.py +2 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/deviation.py +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/downhole_engine.py +14 -15
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/earth_model.py +1 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/example_register_map.json +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/fat_sat.py +1 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/follower.py +6 -6
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/forward_model.py +11 -13
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/gamma.py +3 -3
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/gauge_specs.py +8 -8
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/gravity_reference.py +4 -5
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/inverse_engine.py +2 -2
- gea_program-0.2.0/gea/live_ports.py +166 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/matplotlib_demo.py +2 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/modbus.py +8 -8
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/model_card.py +1 -1
- gea_program-0.2.0/gea/mqtt_port.py +538 -0
- gea_program-0.2.0/gea/opcua_port.py +280 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/operator_app.py +10 -10
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/ports.py +9 -9
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/profile_catalog.py +20 -20
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/project.py +3 -3
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/qt6_downhole_app.py +8 -9
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/quartz_hpht_extension.py +17 -17
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/reconciler.py +3 -3
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/rock_inventory.py +33 -58
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/sample_record.py +2 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/sbom.py +3 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/segy.py +2 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/service_life.py +7 -7
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/strata_join.py +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/survey_cmd.py +3 -4
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/survey_view.py +2 -5
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/telemetry.py +1 -1
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/tool_library.py +9 -9
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/well_assembler.py +12 -13
- {gea_program-0.1.0 → gea_program-0.2.0/gea_program.egg-info}/PKG-INFO +68 -17
- {gea_program-0.1.0 → gea_program-0.2.0}/gea_program.egg-info/SOURCES.txt +3 -1
- gea_program-0.2.0/gea_program.egg-info/requires.txt +25 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/pyproject.toml +6 -2
- {gea_program-0.1.0 → gea_program-0.2.0}/tests/test_acceptance.py +7 -6
- gea_program-0.1.0/gea/IMPORT_RECORD.md +0 -61
- gea_program-0.1.0/gea_program.egg-info/requires.txt +0 -11
- {gea_program-0.1.0 → gea_program-0.2.0}/LICENSE +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/cli.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/config_versioning.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/dashboard.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/shell.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/sla_report.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/store_forward.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.1.0 → gea_program-0.2.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gea-program
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: GEA-Program: downhole gauge monitoring - canonical measurement records, quality rules, drift evaluation with a re-fit change log, well-test validation, alarm management, model cards, store-and-forward, monthly SLA measurement, FAT/SAT protocols and a dashboard, generated from live objects in the client's reporting outline.
|
|
5
5
|
Author: Daniel T. Murphy
|
|
6
6
|
License: MPL-2.0
|
|
@@ -22,6 +22,16 @@ Requires-Dist: PyQt6>=6.5; extra == "desktop"
|
|
|
22
22
|
Requires-Dist: matplotlib>=3.7; extra == "desktop"
|
|
23
23
|
Provides-Extra: modbus
|
|
24
24
|
Requires-Dist: pymodbus>=3.0; extra == "modbus"
|
|
25
|
+
Provides-Extra: opcua
|
|
26
|
+
Requires-Dist: asyncua>=1.0; extra == "opcua"
|
|
27
|
+
Provides-Extra: mqtt
|
|
28
|
+
Requires-Dist: paho-mqtt>=2.0; extra == "mqtt"
|
|
29
|
+
Provides-Extra: live
|
|
30
|
+
Requires-Dist: asyncua>=1.0; extra == "live"
|
|
31
|
+
Requires-Dist: paho-mqtt>=2.0; extra == "live"
|
|
32
|
+
Requires-Dist: pymodbus>=3.0; extra == "live"
|
|
33
|
+
Provides-Extra: xls
|
|
34
|
+
Requires-Dist: xlrd>=2.0; extra == "xls"
|
|
25
35
|
Dynamic: license-file
|
|
26
36
|
|
|
27
37
|
# GEA-Program
|
|
@@ -59,6 +69,12 @@ reaches a client document. Nothing unmeasured is ever reported as met.
|
|
|
59
69
|
rate-controlled replay, duplicate suppression, per-record latency.
|
|
60
70
|
- **Configuration versioning, SBOM, monthly SLA, FAT/SAT**
|
|
61
71
|
(`config_versioning.py`, `sbom.py`, `sla_report.py`, `fat_sat.py`).
|
|
72
|
+
- **Live protocol ports** (`live_ports.py`, `opcua_port.py`, `mqtt_port.py`):
|
|
73
|
+
read-only OPC UA client (read and subscribe) and MQTT subscriber (plain
|
|
74
|
+
number, JSON and Sparkplug B payloads, Sparkplug decoded with no protobuf
|
|
75
|
+
library); every message becomes a measurement record with its source
|
|
76
|
+
timestamp, ingest timestamp and quality flag; every session can be recorded
|
|
77
|
+
and replayed offline. See *Live data* below.
|
|
62
78
|
- **Dashboard** (`dashboard.py`): tiles, well ranking, alarm wall, drill-down to
|
|
63
79
|
every report; light and dark; status is always an icon with a label.
|
|
64
80
|
- **Survey track** (`earth_model.py`, `strata_join.py`, `inverse_engine.py`,
|
|
@@ -75,7 +91,7 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
|
|
|
75
91
|
gea client-report --report accuracy --out client_report
|
|
76
92
|
gea model-cards --out model_cards
|
|
77
93
|
gea sbom --out sbom
|
|
78
|
-
gea accept # the product gate (
|
|
94
|
+
gea accept # the product gate (172 checks)
|
|
79
95
|
gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
|
|
80
96
|
gea gui # the desktop window (pip install "gea-program[desktop]")
|
|
81
97
|
```
|
|
@@ -83,28 +99,62 @@ gea gui # the desktop window (pip install "gea-program[de
|
|
|
83
99
|
`gea` is the front door (`gea/cli.py`); every other subcommand passes through to
|
|
84
100
|
`python -m gea`. PATH-proof form: `python -m gea.cli ...`. Open `dashboard/index.html`.
|
|
85
101
|
|
|
102
|
+
## Live data
|
|
103
|
+
|
|
104
|
+
The engine reads live data through two protocol ports. Both are **read-only**,
|
|
105
|
+
both map only what the site declares (a tag map the client owns; an empty map
|
|
106
|
+
is declined), and both write every received message to a JSON-lines recording
|
|
107
|
+
that `--replay` turns back into records without a connection - which is how a
|
|
108
|
+
site session is reproduced offline and how the mapping logic is tested.
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
pip install "gea-program[live]" # asyncua + paho-mqtt (or [opcua] / [mqtt] alone)
|
|
112
|
+
gea opcua --write-example-config opcua.json # edit: endpoint, security, credential env names, nodes
|
|
113
|
+
gea opcua --config opcua.json --read-once --out opc # one read of every mapped node
|
|
114
|
+
gea opcua --config opcua.json --seconds 60 --record opc/session.jsonl --out opc --stream-csv opc/stream.csv
|
|
115
|
+
gea mqtt --write-example-config mqtt.json # edit: broker, TLS, credential env names, topics
|
|
116
|
+
gea mqtt --config mqtt.json --seconds 60 --record mq/session.jsonl --out mq --stream-csv mq/stream.csv
|
|
117
|
+
gea mqtt --config mqtt.json --replay mq/session.jsonl --out mq_replay # no broker needed
|
|
118
|
+
gea ingest --file mq/stream.csv # the stream CSV feeds the historian port like any other
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| port | transport | quality | timestamps |
|
|
122
|
+
|---|---|---|---|
|
|
123
|
+
| `opcua` | opc.tcp, read + subscribe; Basic256Sha256 SignAndEncrypt when a certificate and key are given | StatusCode severity bits: Good -> GOOD, Uncertain -> STALE, Bad -> GAP (value withheld); the rule names the code | source timestamp, else server timestamp, else arrival; ingest stamped at arrival |
|
|
124
|
+
| `mqtt` | MQTT v5 / v3.1.1, TLS optional, QoS per topic; `+`/`#` wildcards | number: GOOD or GAP (unparseable, reason kept); JSON: value/time/quality paths and the list of good values; Sparkplug B: `is_null` -> GAP, `Quality` property != 192 -> STALE | JSON time path (ISO / epoch s / epoch ms), Sparkplug metric timestamp, else arrival |
|
|
125
|
+
|
|
126
|
+
Credentials never sit in a config file: the file names the environment variables
|
|
127
|
+
that hold them (`GEA_OPCUA_USER`, `GEA_MQTT_PASSWORD`, ...). Sparkplug B aliases
|
|
128
|
+
are learned from any NBIRTH/DBIRTH on the matching edge node, so alias-only DDATA
|
|
129
|
+
resolves. The example configs are in `docs/examples/`; the acceptance suite
|
|
130
|
+
section AB covers the codec, the mappings, the quality rules, replay and the
|
|
131
|
+
hand-off to the store-and-forward buffer, and runs a live in-process OPC UA
|
|
132
|
+
loopback wherever `asyncua` is installed.
|
|
133
|
+
|
|
86
134
|
## Layout
|
|
87
135
|
|
|
88
136
|
```
|
|
89
137
|
gea/ the package: engines, record layer, reports, monitor, dashboard, cli, shell, acceptance suite
|
|
90
138
|
gea/catalog/ 52 public archive entries, each with a provenance file
|
|
91
|
-
docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports),
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
139
|
+
docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports), examples/ (port configs),
|
|
140
|
+
SESSION_LOG.md (the working record, session by session),
|
|
141
|
+
commercial/ (pilot proposal, bench readiness, commercial use), HISTORY.md (the ship-by-ship record)
|
|
142
|
+
tools/ standalone_check.py (the self-contained guard: imports, text, metadata; run by ci and ship.ps1)
|
|
143
|
+
CHANGELOG.md per-release summary (a tag ships only with its section); SHIP_LOG.md is written by ship.ps1
|
|
144
|
+
tests/ pytest wrapper around the acceptance suite and the standalone check
|
|
95
145
|
```
|
|
96
146
|
|
|
97
|
-
##
|
|
147
|
+
## Basis
|
|
98
148
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
149
|
+
GEA-Program is a self-contained package: every module imports only the
|
|
150
|
+
standard library, numpy, the declared optional extras and the package itself,
|
|
151
|
+
and `tools/standalone_check.py` (run by CI and by `ship.ps1`) fails the build
|
|
152
|
+
if that ever changes or if a tracked file names another program. The physics
|
|
153
|
+
is on standard constants - CODATA 2018 G, standard gravity 9.80665 m/s2, the
|
|
154
|
+
IUGG mean Earth radius - and the rock inventory carries seventeen published
|
|
155
|
+
density anchors and Vp ranges with their citations (Telford, Geldart and
|
|
156
|
+
Sheriff; Schon). Every catalogue entry under `gea/catalog/` has a provenance
|
|
157
|
+
file naming its public source.
|
|
108
158
|
|
|
109
159
|
Two statements the product carries on its own model cards: the gauge aging
|
|
110
160
|
envelope's lower bound is an engineering model with no field validation on
|
|
@@ -117,7 +167,8 @@ ACCEPTABLE at the 95 % target. Both are printed, never claimed otherwise.
|
|
|
117
167
|
`pyproject.toml` must equal `gea.__version__` (`-Bump x.y.z` sets both), the tag must
|
|
118
168
|
not exist anywhere, every version in `SHIP_LOG.md` must have its tag, `python -m gea
|
|
119
169
|
accept` must be green, `SHIP_MESSAGE.txt` must start with the tag; then commit, tag,
|
|
120
|
-
push, and the remote tag must be seen before SHIPPED is printed.
|
|
170
|
+
push, and the remote tag must be seen before SHIPPED is printed. `CHANGELOG.md` must carry a
|
|
171
|
+
section headed by the tag, and `tools/standalone_check.py` must report no findings. `-DryRun` runs every
|
|
121
172
|
check and changes nothing; `-NoPush` stops after the local tag.
|
|
122
173
|
|
|
123
174
|
## Publishing to PyPI
|
|
@@ -33,6 +33,12 @@ reaches a client document. Nothing unmeasured is ever reported as met.
|
|
|
33
33
|
rate-controlled replay, duplicate suppression, per-record latency.
|
|
34
34
|
- **Configuration versioning, SBOM, monthly SLA, FAT/SAT**
|
|
35
35
|
(`config_versioning.py`, `sbom.py`, `sla_report.py`, `fat_sat.py`).
|
|
36
|
+
- **Live protocol ports** (`live_ports.py`, `opcua_port.py`, `mqtt_port.py`):
|
|
37
|
+
read-only OPC UA client (read and subscribe) and MQTT subscriber (plain
|
|
38
|
+
number, JSON and Sparkplug B payloads, Sparkplug decoded with no protobuf
|
|
39
|
+
library); every message becomes a measurement record with its source
|
|
40
|
+
timestamp, ingest timestamp and quality flag; every session can be recorded
|
|
41
|
+
and replayed offline. See *Live data* below.
|
|
36
42
|
- **Dashboard** (`dashboard.py`): tiles, well ranking, alarm wall, drill-down to
|
|
37
43
|
every report; light and dark; status is always an icon with a label.
|
|
38
44
|
- **Survey track** (`earth_model.py`, `strata_join.py`, `inverse_engine.py`,
|
|
@@ -49,7 +55,7 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
|
|
|
49
55
|
gea client-report --report accuracy --out client_report
|
|
50
56
|
gea model-cards --out model_cards
|
|
51
57
|
gea sbom --out sbom
|
|
52
|
-
gea accept # the product gate (
|
|
58
|
+
gea accept # the product gate (172 checks)
|
|
53
59
|
gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
|
|
54
60
|
gea gui # the desktop window (pip install "gea-program[desktop]")
|
|
55
61
|
```
|
|
@@ -57,28 +63,62 @@ gea gui # the desktop window (pip install "gea-program[de
|
|
|
57
63
|
`gea` is the front door (`gea/cli.py`); every other subcommand passes through to
|
|
58
64
|
`python -m gea`. PATH-proof form: `python -m gea.cli ...`. Open `dashboard/index.html`.
|
|
59
65
|
|
|
66
|
+
## Live data
|
|
67
|
+
|
|
68
|
+
The engine reads live data through two protocol ports. Both are **read-only**,
|
|
69
|
+
both map only what the site declares (a tag map the client owns; an empty map
|
|
70
|
+
is declined), and both write every received message to a JSON-lines recording
|
|
71
|
+
that `--replay` turns back into records without a connection - which is how a
|
|
72
|
+
site session is reproduced offline and how the mapping logic is tested.
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
pip install "gea-program[live]" # asyncua + paho-mqtt (or [opcua] / [mqtt] alone)
|
|
76
|
+
gea opcua --write-example-config opcua.json # edit: endpoint, security, credential env names, nodes
|
|
77
|
+
gea opcua --config opcua.json --read-once --out opc # one read of every mapped node
|
|
78
|
+
gea opcua --config opcua.json --seconds 60 --record opc/session.jsonl --out opc --stream-csv opc/stream.csv
|
|
79
|
+
gea mqtt --write-example-config mqtt.json # edit: broker, TLS, credential env names, topics
|
|
80
|
+
gea mqtt --config mqtt.json --seconds 60 --record mq/session.jsonl --out mq --stream-csv mq/stream.csv
|
|
81
|
+
gea mqtt --config mqtt.json --replay mq/session.jsonl --out mq_replay # no broker needed
|
|
82
|
+
gea ingest --file mq/stream.csv # the stream CSV feeds the historian port like any other
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| port | transport | quality | timestamps |
|
|
86
|
+
|---|---|---|---|
|
|
87
|
+
| `opcua` | opc.tcp, read + subscribe; Basic256Sha256 SignAndEncrypt when a certificate and key are given | StatusCode severity bits: Good -> GOOD, Uncertain -> STALE, Bad -> GAP (value withheld); the rule names the code | source timestamp, else server timestamp, else arrival; ingest stamped at arrival |
|
|
88
|
+
| `mqtt` | MQTT v5 / v3.1.1, TLS optional, QoS per topic; `+`/`#` wildcards | number: GOOD or GAP (unparseable, reason kept); JSON: value/time/quality paths and the list of good values; Sparkplug B: `is_null` -> GAP, `Quality` property != 192 -> STALE | JSON time path (ISO / epoch s / epoch ms), Sparkplug metric timestamp, else arrival |
|
|
89
|
+
|
|
90
|
+
Credentials never sit in a config file: the file names the environment variables
|
|
91
|
+
that hold them (`GEA_OPCUA_USER`, `GEA_MQTT_PASSWORD`, ...). Sparkplug B aliases
|
|
92
|
+
are learned from any NBIRTH/DBIRTH on the matching edge node, so alias-only DDATA
|
|
93
|
+
resolves. The example configs are in `docs/examples/`; the acceptance suite
|
|
94
|
+
section AB covers the codec, the mappings, the quality rules, replay and the
|
|
95
|
+
hand-off to the store-and-forward buffer, and runs a live in-process OPC UA
|
|
96
|
+
loopback wherever `asyncua` is installed.
|
|
97
|
+
|
|
60
98
|
## Layout
|
|
61
99
|
|
|
62
100
|
```
|
|
63
101
|
gea/ the package: engines, record layer, reports, monitor, dashboard, cli, shell, acceptance suite
|
|
64
102
|
gea/catalog/ 52 public archive entries, each with a provenance file
|
|
65
|
-
docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports),
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
103
|
+
docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports), examples/ (port configs),
|
|
104
|
+
SESSION_LOG.md (the working record, session by session),
|
|
105
|
+
commercial/ (pilot proposal, bench readiness, commercial use), HISTORY.md (the ship-by-ship record)
|
|
106
|
+
tools/ standalone_check.py (the self-contained guard: imports, text, metadata; run by ci and ship.ps1)
|
|
107
|
+
CHANGELOG.md per-release summary (a tag ships only with its section); SHIP_LOG.md is written by ship.ps1
|
|
108
|
+
tests/ pytest wrapper around the acceptance suite and the standalone check
|
|
69
109
|
```
|
|
70
110
|
|
|
71
|
-
##
|
|
111
|
+
## Basis
|
|
72
112
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
113
|
+
GEA-Program is a self-contained package: every module imports only the
|
|
114
|
+
standard library, numpy, the declared optional extras and the package itself,
|
|
115
|
+
and `tools/standalone_check.py` (run by CI and by `ship.ps1`) fails the build
|
|
116
|
+
if that ever changes or if a tracked file names another program. The physics
|
|
117
|
+
is on standard constants - CODATA 2018 G, standard gravity 9.80665 m/s2, the
|
|
118
|
+
IUGG mean Earth radius - and the rock inventory carries seventeen published
|
|
119
|
+
density anchors and Vp ranges with their citations (Telford, Geldart and
|
|
120
|
+
Sheriff; Schon). Every catalogue entry under `gea/catalog/` has a provenance
|
|
121
|
+
file naming its public source.
|
|
82
122
|
|
|
83
123
|
Two statements the product carries on its own model cards: the gauge aging
|
|
84
124
|
envelope's lower bound is an engineering model with no field validation on
|
|
@@ -91,7 +131,8 @@ ACCEPTABLE at the 95 % target. Both are printed, never claimed otherwise.
|
|
|
91
131
|
`pyproject.toml` must equal `gea.__version__` (`-Bump x.y.z` sets both), the tag must
|
|
92
132
|
not exist anywhere, every version in `SHIP_LOG.md` must have its tag, `python -m gea
|
|
93
133
|
accept` must be green, `SHIP_MESSAGE.txt` must start with the tag; then commit, tag,
|
|
94
|
-
push, and the remote tag must be seen before SHIPPED is printed.
|
|
134
|
+
push, and the remote tag must be seen before SHIPPED is printed. `CHANGELOG.md` must carry a
|
|
135
|
+
section headed by the tag, and `tools/standalone_check.py` must report no findings. `-DryRun` runs every
|
|
95
136
|
check and changes nothing; `-NoPush` stops after the local tag.
|
|
96
137
|
|
|
97
138
|
## Publishing to PyPI
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# Bench-Test Protocol — Measuring the 1.0324 Suppression Ratio
|
|
2
2
|
|
|
3
|
-
**Field-tier step 8 (independent evaluation, adopted 2026-08-27).**
|
|
4
3
|
Status of the quantity under test: `canonical_suppression()` = **1.0324 at
|
|
5
4
|
unity trims** is today a **DERIVED_HYBRID** composition — industry baseline
|
|
6
5
|
drift (0.215 %FS/yr class) with HPHT stress dressing, divided by a
|
|
7
|
-
|
|
6
|
+
the program's suppression composition of three locked constants. It is **not** a measured constant, and the
|
|
8
7
|
product labels it so everywhere it appears. This protocol is the experiment
|
|
9
8
|
that would change — or refuse to change — that label.
|
|
10
9
|
|
|
@@ -77,7 +76,7 @@ product's own honesty rule.
|
|
|
77
76
|
|
|
78
77
|
- **Confirmed:** `canonical_suppression()`'s label may move from
|
|
79
78
|
DERIVED_HYBRID to MEASURED_ON_BENCH **with the test ID, dates, apparatus
|
|
80
|
-
and per-pair results attached**. The composition's
|
|
79
|
+
and per-pair results attached**. The composition's constants are then a
|
|
81
80
|
measured-consistent model, not just a labeled one.
|
|
82
81
|
- **Refuted:** the label stays DERIVED_HYBRID; the refutation (conditions,
|
|
83
82
|
measured R, uncertainty) is recorded beside it. No silent retuning of
|
|
@@ -8,10 +8,10 @@ deep-well (TD ~20,300 ft) six-gauge quartz P/T string with GEA-stabilized
|
|
|
8
8
|
drift, transient events, live animation (matplotlib / optional PyQt6), and
|
|
9
9
|
CSV export.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
The program aging model composes a fixed drift-suppression factor from three
|
|
12
|
+
locked engineering constants (K_MEX = 25/12, PHI_RES = 0.84, F_TRZ = 0.1); the
|
|
13
|
+
user-facing settings are the two instrument trims (k_structural_trim,
|
|
14
|
+
phi_coupling_trim), never the constants. See README.md.
|
|
15
15
|
|
|
16
16
|
Quick use (headless):
|
|
17
17
|
from gea import DownholeEngine, SimulatorConfig
|
|
@@ -97,6 +97,8 @@ from .modbus import (
|
|
|
97
97
|
RegisterMap,
|
|
98
98
|
load_register_map,
|
|
99
99
|
)
|
|
100
|
+
from .opcua_port import ASYNCUA_AVAILABLE, OpcUaTap # registers the 'opcua' port at import
|
|
101
|
+
from .mqtt_port import PAHO_AVAILABLE, MqttTap # registers the 'mqtt' port at import
|
|
100
102
|
from .well_assembler import (
|
|
101
103
|
WellAssembly, WellComponent, assemble, assemble_ktb_hb, assemble_odp_504b,
|
|
102
104
|
assemble_site_1027, assemble_u1324, BUILTIN_ASSEMBLIES,
|
|
@@ -125,7 +127,7 @@ from .profile_catalog import (
|
|
|
125
127
|
read_pangaea_txt,
|
|
126
128
|
)
|
|
127
129
|
|
|
128
|
-
__version__ = "0.
|
|
130
|
+
__version__ = "0.2.0"
|
|
129
131
|
__all__ = [
|
|
130
132
|
"calculate_quartz_transducer_hpht_program", "canonical_suppression",
|
|
131
133
|
"conventional_drift", "drift_comparison",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
"""Headless CLI for the GEA Downhole Simulator
|
|
4
|
+
"""Headless CLI for the GEA Downhole Simulator.
|
|
5
5
|
|
|
6
6
|
python -m gea run --steps 200 --out run.csv
|
|
7
7
|
python -m gea service-life --years 5 --out curves.csv
|
|
@@ -250,6 +250,18 @@ def main(argv=None) -> int:
|
|
|
250
250
|
p_db.add_argument("--name", type=str, default="site")
|
|
251
251
|
p_db.add_argument("--out", type=str, default="dashboard")
|
|
252
252
|
|
|
253
|
+
for name, helptxt in (("opcua", "OPC UA client port: read once or subscribe; record; replay a recording offline"),
|
|
254
|
+
("mqtt", "MQTT subscriber port (3.1.1/5.0; number | json | Sparkplug B): run; record; replay offline")):
|
|
255
|
+
p_lp = sub.add_parser(name, help=helptxt)
|
|
256
|
+
p_lp.add_argument("--config", type=str, default=None, help="site map JSON (client-owned)")
|
|
257
|
+
p_lp.add_argument("--write-example-config", type=str, default=None, help="write an example map here and exit")
|
|
258
|
+
p_lp.add_argument("--replay", type=str, default=None, help="recording (JSON lines) to replay instead of connecting")
|
|
259
|
+
p_lp.add_argument("--record", type=str, default=None, help="write every received message to this recording")
|
|
260
|
+
p_lp.add_argument("--seconds", type=float, default=10.0, help="subscribe/run duration")
|
|
261
|
+
p_lp.add_argument("--read-once", action="store_true", help="opcua: one Read of all nodes instead of a subscription")
|
|
262
|
+
p_lp.add_argument("--out", type=str, default=None, help="write the records CSV here")
|
|
263
|
+
p_lp.add_argument("--stream-csv", type=str, default=None, help="also write a historian-style CSV the other commands ingest")
|
|
264
|
+
|
|
253
265
|
p_cs = sub.add_parser("case-study", help="depth sweep, write the one-page markdown case")
|
|
254
266
|
_add_well_args(p_cs)
|
|
255
267
|
p_cs.add_argument("--points", type=int, default=12)
|
|
@@ -339,7 +351,7 @@ def main(argv=None) -> int:
|
|
|
339
351
|
asm = maker()
|
|
340
352
|
except Exception:
|
|
341
353
|
# operator-tier assemblies on machines without the private
|
|
342
|
-
# data: listed
|
|
354
|
+
# data: listed plainly, never crashing the listing
|
|
343
355
|
print(f"{name}: OPERATOR-TIER assembly - private data not "
|
|
344
356
|
"present on this machine (tier is per-machine, never required)")
|
|
345
357
|
continue
|
|
@@ -372,6 +384,47 @@ def main(argv=None) -> int:
|
|
|
372
384
|
rep = Reconciler(_build_config(a)).reconcile(stream, station_map=station_map)
|
|
373
385
|
import json as _json
|
|
374
386
|
print(_json.dumps(rep, indent=1))
|
|
387
|
+
elif a.cmd in ("opcua", "mqtt"):
|
|
388
|
+
import json as _json
|
|
389
|
+
from .live_ports import records_to_stream, summarize, write_records_csv
|
|
390
|
+
mod = __import__("gea.opcua_port" if a.cmd == "opcua" else "gea.mqtt_port", fromlist=["x"])
|
|
391
|
+
if a.write_example_config:
|
|
392
|
+
print("config:", mod.write_example_config(a.write_example_config))
|
|
393
|
+
return 0
|
|
394
|
+
if not a.config:
|
|
395
|
+
raise SystemExit(f"{a.cmd} needs --config (or --write-example-config to start one)")
|
|
396
|
+
try:
|
|
397
|
+
if a.replay:
|
|
398
|
+
recs = mod.replay(a.config, a.replay)
|
|
399
|
+
src = f"replay {a.replay}"
|
|
400
|
+
elif a.cmd == "opcua":
|
|
401
|
+
tap = mod.OpcUaTap(a.config, recording_path=a.record).connect()
|
|
402
|
+
try:
|
|
403
|
+
recs = tap.read_once() if a.read_once else tap.subscribe(a.seconds)
|
|
404
|
+
finally:
|
|
405
|
+
tap.close()
|
|
406
|
+
src = tap.cfg["endpoint"]
|
|
407
|
+
else:
|
|
408
|
+
tap = mod.MqttTap(a.config, recording_path=a.record)
|
|
409
|
+
recs = tap.run(a.seconds)
|
|
410
|
+
src = tap.cfg["broker"]["host"]
|
|
411
|
+
except (NotImplementedError, ConnectionError, ValueError) as e:
|
|
412
|
+
raise SystemExit(f"{a.cmd}: {e}") # the reason, without a traceback
|
|
413
|
+
print(f"{a.cmd}: {src}")
|
|
414
|
+
print(_json.dumps(summarize(recs), indent=1))
|
|
415
|
+
if a.out:
|
|
416
|
+
print(" records:", write_records_csv(recs, a.out))
|
|
417
|
+
if a.stream_csv and recs:
|
|
418
|
+
st = records_to_stream(recs, name=a.cmd)
|
|
419
|
+
import csv as _csv
|
|
420
|
+
from datetime import datetime as _dt, timedelta as _td
|
|
421
|
+
t0 = _dt.fromisoformat(st.meta["start_time"])
|
|
422
|
+
with open(a.stream_csv, "w", newline="", encoding="utf-8") as f:
|
|
423
|
+
w = _csv.writer(f)
|
|
424
|
+
w.writerow(["timestamp"] + list(st.channels))
|
|
425
|
+
for i, t in enumerate(st.index):
|
|
426
|
+
w.writerow([(t0 + _td(seconds=float(t))).isoformat()] + ["" if st.channels[c].values[i] != st.channels[c].values[i] else round(float(st.channels[c].values[i]), 4) for c in st.channels])
|
|
427
|
+
print(" stream:", a.stream_csv)
|
|
375
428
|
elif a.cmd == "dashboard":
|
|
376
429
|
from . import GAUGE_SPECS, load_gauge_spec_json, DEFAULT_TD_FT
|
|
377
430
|
from .dashboard import orchestrate
|