gea-program 0.22.0__tar.gz → 0.24.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.
Files changed (263) hide show
  1. {gea_program-0.22.0 → gea_program-0.24.0}/PKG-INFO +35 -2
  2. {gea_program-0.22.0 → gea_program-0.24.0}/README.md +34 -1
  3. {gea_program-0.22.0 → gea_program-0.24.0}/gea/__init__.py +1 -1
  4. {gea_program-0.22.0 → gea_program-0.24.0}/gea/__main__.py +204 -5
  5. {gea_program-0.22.0 → gea_program-0.24.0}/gea/acceptance_tests.py +373 -0
  6. gea_program-0.24.0/gea/dlis.py +624 -0
  7. gea_program-0.24.0/gea/dnp3.py +614 -0
  8. {gea_program-0.22.0 → gea_program-0.24.0}/gea/files.py +18 -2
  9. gea_program-0.24.0/gea/hartip.py +513 -0
  10. gea_program-0.24.0/gea/help/dlis.md +11 -0
  11. gea_program-0.24.0/gea/help/field-ports.md +11 -0
  12. gea_program-0.24.0/gea/help/historian.md +11 -0
  13. {gea_program-0.22.0 → gea_program-0.24.0}/gea/helplib.py +3 -0
  14. gea_program-0.24.0/gea/modbus_rtu.py +439 -0
  15. {gea_program-0.22.0 → gea_program-0.24.0}/gea/patches.py +96 -3
  16. gea_program-0.24.0/gea/piwebapi.py +366 -0
  17. {gea_program-0.22.0 → gea_program-0.24.0}/gea/ports.py +4 -0
  18. {gea_program-0.22.0 → gea_program-0.24.0}/gea/service.py +6 -2
  19. {gea_program-0.22.0 → gea_program-0.24.0}/gea/survey_cmd.py +13 -3
  20. {gea_program-0.22.0 → gea_program-0.24.0}/gea/web/app.html +1 -1
  21. {gea_program-0.22.0 → gea_program-0.24.0}/gea/workspace.py +1 -1
  22. {gea_program-0.22.0 → gea_program-0.24.0}/gea_program.egg-info/PKG-INFO +35 -2
  23. {gea_program-0.22.0 → gea_program-0.24.0}/gea_program.egg-info/SOURCES.txt +8 -0
  24. {gea_program-0.22.0 → gea_program-0.24.0}/pyproject.toml +1 -1
  25. {gea_program-0.22.0 → gea_program-0.24.0}/LICENSE +0 -0
  26. {gea_program-0.22.0 → gea_program-0.24.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  27. {gea_program-0.22.0 → gea_program-0.24.0}/gea/accuracy_statement.py +0 -0
  28. {gea_program-0.22.0 → gea_program-0.24.0}/gea/alarm_engine.py +0 -0
  29. {gea_program-0.22.0 → gea_program-0.24.0}/gea/backup.py +0 -0
  30. {gea_program-0.22.0 → gea_program-0.24.0}/gea/bench.py +0 -0
  31. {gea_program-0.22.0 → gea_program-0.24.0}/gea/blind_harness.py +0 -0
  32. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  33. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  34. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  35. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  36. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  37. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  38. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  39. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  40. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  41. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  42. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  43. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  44. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  45. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  46. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  47. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  48. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  49. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  50. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  51. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  52. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  53. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  54. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  55. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  56. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  57. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  58. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  59. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  60. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  61. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  62. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  63. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  64. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  65. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  66. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  67. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  68. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  69. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  70. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  71. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  72. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  73. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  74. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  75. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  76. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  77. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  78. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  79. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  80. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  81. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  82. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  83. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  84. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  85. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  86. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  87. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  88. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  89. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  90. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  91. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  92. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  93. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  94. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  95. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  96. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  97. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  98. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  99. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/med_160_sapropels.txt +0 -0
  100. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  101. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  102. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  103. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  104. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  105. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  106. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  107. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  108. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  109. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  110. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  111. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  112. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  113. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  114. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  115. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  116. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  117. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  118. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  119. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  120. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  121. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  122. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  123. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  124. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  125. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  126. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  127. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  128. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  129. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  130. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  131. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  132. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  133. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  134. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  135. {gea_program-0.22.0 → gea_program-0.24.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  136. {gea_program-0.22.0 → gea_program-0.24.0}/gea/certificates.py +0 -0
  137. {gea_program-0.22.0 → gea_program-0.24.0}/gea/cli.py +0 -0
  138. {gea_program-0.22.0 → gea_program-0.24.0}/gea/client_reports.py +0 -0
  139. {gea_program-0.22.0 → gea_program-0.24.0}/gea/config_versioning.py +0 -0
  140. {gea_program-0.22.0 → gea_program-0.24.0}/gea/conformance.py +0 -0
  141. {gea_program-0.22.0 → gea_program-0.24.0}/gea/correlation.py +0 -0
  142. {gea_program-0.22.0 → gea_program-0.24.0}/gea/dashboard.py +0 -0
  143. {gea_program-0.22.0 → gea_program-0.24.0}/gea/deviation.py +0 -0
  144. {gea_program-0.22.0 → gea_program-0.24.0}/gea/doctor.py +0 -0
  145. {gea_program-0.22.0 → gea_program-0.24.0}/gea/downhole_engine.py +0 -0
  146. {gea_program-0.22.0 → gea_program-0.24.0}/gea/drift_monitor.py +0 -0
  147. {gea_program-0.22.0 → gea_program-0.24.0}/gea/earth_model.py +0 -0
  148. {gea_program-0.22.0 → gea_program-0.24.0}/gea/elevation.py +0 -0
  149. {gea_program-0.22.0 → gea_program-0.24.0}/gea/etp.py +0 -0
  150. {gea_program-0.22.0 → gea_program-0.24.0}/gea/etp12_schemas.json +0 -0
  151. {gea_program-0.22.0 → gea_program-0.24.0}/gea/example_register_map.json +0 -0
  152. {gea_program-0.22.0 → gea_program-0.24.0}/gea/fat_sat.py +0 -0
  153. {gea_program-0.22.0 → gea_program-0.24.0}/gea/follower.py +0 -0
  154. {gea_program-0.22.0 → gea_program-0.24.0}/gea/forward_model.py +0 -0
  155. {gea_program-0.22.0 → gea_program-0.24.0}/gea/gamma.py +0 -0
  156. {gea_program-0.22.0 → gea_program-0.24.0}/gea/gauge_aging.py +0 -0
  157. {gea_program-0.22.0 → gea_program-0.24.0}/gea/gauge_specs.py +0 -0
  158. {gea_program-0.22.0 → gea_program-0.24.0}/gea/geodesy.py +0 -0
  159. {gea_program-0.22.0 → gea_program-0.24.0}/gea/gravity_reference.py +0 -0
  160. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/TESTER_GUIDE.md +0 -0
  161. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/alarms.md +0 -0
  162. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/audit-update.md +0 -0
  163. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/backup.md +0 -0
  164. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/conformance.md +0 -0
  165. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/data-in.md +0 -0
  166. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/doctor.md +0 -0
  167. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/drift.md +0 -0
  168. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/etp.md +0 -0
  169. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/files.md +0 -0
  170. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/instruments.md +0 -0
  171. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/interval.md +0 -0
  172. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/month-end.md +0 -0
  173. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/notifications.md +0 -0
  174. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/osdu.md +0 -0
  175. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/patches.md +0 -0
  176. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/ppdm.md +0 -0
  177. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/quakeml.md +0 -0
  178. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/quality.md +0 -0
  179. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/seedlink.md +0 -0
  180. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/seismic.md +0 -0
  181. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/site.md +0 -0
  182. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/sites.md +0 -0
  183. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/soak.md +0 -0
  184. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/sra.md +0 -0
  185. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/start.md +0 -0
  186. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/structure.md +0 -0
  187. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/transients.md +0 -0
  188. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/upkeep.md +0 -0
  189. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/vibration.md +0 -0
  190. {gea_program-0.22.0 → gea_program-0.24.0}/gea/help/well-tests.md +0 -0
  191. {gea_program-0.22.0 → gea_program-0.24.0}/gea/housekeeping.py +0 -0
  192. {gea_program-0.22.0 → gea_program-0.24.0}/gea/interval.py +0 -0
  193. {gea_program-0.22.0 → gea_program-0.24.0}/gea/inverse_engine.py +0 -0
  194. {gea_program-0.22.0 → gea_program-0.24.0}/gea/jobs.py +0 -0
  195. {gea_program-0.22.0 → gea_program-0.24.0}/gea/live_ports.py +0 -0
  196. {gea_program-0.22.0 → gea_program-0.24.0}/gea/loadtest.py +0 -0
  197. {gea_program-0.22.0 → gea_program-0.24.0}/gea/matplotlib_demo.py +0 -0
  198. {gea_program-0.22.0 → gea_program-0.24.0}/gea/modbus.py +0 -0
  199. {gea_program-0.22.0 → gea_program-0.24.0}/gea/model_card.py +0 -0
  200. {gea_program-0.22.0 → gea_program-0.24.0}/gea/month_end.py +0 -0
  201. {gea_program-0.22.0 → gea_program-0.24.0}/gea/mqtt_port.py +0 -0
  202. {gea_program-0.22.0 → gea_program-0.24.0}/gea/notify.py +0 -0
  203. {gea_program-0.22.0 → gea_program-0.24.0}/gea/opcua_port.py +0 -0
  204. {gea_program-0.22.0 → gea_program-0.24.0}/gea/operator_app.py +0 -0
  205. {gea_program-0.22.0 → gea_program-0.24.0}/gea/osdu.py +0 -0
  206. {gea_program-0.22.0 → gea_program-0.24.0}/gea/permits.py +0 -0
  207. {gea_program-0.22.0 → gea_program-0.24.0}/gea/ppdm.py +0 -0
  208. {gea_program-0.22.0 → gea_program-0.24.0}/gea/profile_catalog.py +0 -0
  209. {gea_program-0.22.0 → gea_program-0.24.0}/gea/project.py +0 -0
  210. {gea_program-0.22.0 → gea_program-0.24.0}/gea/qt6_downhole_app.py +0 -0
  211. {gea_program-0.22.0 → gea_program-0.24.0}/gea/quakeml.py +0 -0
  212. {gea_program-0.22.0 → gea_program-0.24.0}/gea/reconciler.py +0 -0
  213. {gea_program-0.22.0 → gea_program-0.24.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  214. {gea_program-0.22.0 → gea_program-0.24.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  215. {gea_program-0.22.0 → gea_program-0.24.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  216. {gea_program-0.22.0 → gea_program-0.24.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  217. {gea_program-0.22.0 → gea_program-0.24.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  218. {gea_program-0.22.0 → gea_program-0.24.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  219. {gea_program-0.22.0 → gea_program-0.24.0}/gea/rock_inventory.py +0 -0
  220. {gea_program-0.22.0 → gea_program-0.24.0}/gea/sample_record.py +0 -0
  221. {gea_program-0.22.0 → gea_program-0.24.0}/gea/sample_well_profile.csv +0 -0
  222. {gea_program-0.22.0 → gea_program-0.24.0}/gea/sbom.py +0 -0
  223. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seedlink.py +0 -0
  224. {gea_program-0.22.0 → gea_program-0.24.0}/gea/segy.py +0 -0
  225. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic.py +0 -0
  226. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_array.py +0 -0
  227. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_assoc.py +0 -0
  228. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_detect.py +0 -0
  229. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_film.py +0 -0
  230. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_harmonic.py +0 -0
  231. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_qc.py +0 -0
  232. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_response.py +0 -0
  233. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_signature.py +0 -0
  234. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_track.py +0 -0
  235. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_uncertainty.py +0 -0
  236. {gea_program-0.22.0 → gea_program-0.24.0}/gea/seismic_unlisted.py +0 -0
  237. {gea_program-0.22.0 → gea_program-0.24.0}/gea/sensor_swap.py +0 -0
  238. {gea_program-0.22.0 → gea_program-0.24.0}/gea/service_life.py +0 -0
  239. {gea_program-0.22.0 → gea_program-0.24.0}/gea/shapefile.py +0 -0
  240. {gea_program-0.22.0 → gea_program-0.24.0}/gea/shell.py +0 -0
  241. {gea_program-0.22.0 → gea_program-0.24.0}/gea/shut_in.py +0 -0
  242. {gea_program-0.22.0 → gea_program-0.24.0}/gea/sla_report.py +0 -0
  243. {gea_program-0.22.0 → gea_program-0.24.0}/gea/soak.py +0 -0
  244. {gea_program-0.22.0 → gea_program-0.24.0}/gea/sra.py +0 -0
  245. {gea_program-0.22.0 → gea_program-0.24.0}/gea/store_forward.py +0 -0
  246. {gea_program-0.22.0 → gea_program-0.24.0}/gea/strata_join.py +0 -0
  247. {gea_program-0.22.0 → gea_program-0.24.0}/gea/structure.py +0 -0
  248. {gea_program-0.22.0 → gea_program-0.24.0}/gea/supervisor.py +0 -0
  249. {gea_program-0.22.0 → gea_program-0.24.0}/gea/survey_view.py +0 -0
  250. {gea_program-0.22.0 → gea_program-0.24.0}/gea/telemetry.py +0 -0
  251. {gea_program-0.22.0 → gea_program-0.24.0}/gea/tool_library.py +0 -0
  252. {gea_program-0.22.0 → gea_program-0.24.0}/gea/transient.py +0 -0
  253. {gea_program-0.22.0 → gea_program-0.24.0}/gea/vibration.py +0 -0
  254. {gea_program-0.22.0 → gea_program-0.24.0}/gea/well_assembler.py +0 -0
  255. {gea_program-0.22.0 → gea_program-0.24.0}/gea/well_test_validation.py +0 -0
  256. {gea_program-0.22.0 → gea_program-0.24.0}/gea/wits0.py +0 -0
  257. {gea_program-0.22.0 → gea_program-0.24.0}/gea/witsml.py +0 -0
  258. {gea_program-0.22.0 → gea_program-0.24.0}/gea_program.egg-info/dependency_links.txt +0 -0
  259. {gea_program-0.22.0 → gea_program-0.24.0}/gea_program.egg-info/entry_points.txt +0 -0
  260. {gea_program-0.22.0 → gea_program-0.24.0}/gea_program.egg-info/requires.txt +0 -0
  261. {gea_program-0.22.0 → gea_program-0.24.0}/gea_program.egg-info/top_level.txt +0 -0
  262. {gea_program-0.22.0 → gea_program-0.24.0}/setup.cfg +0 -0
  263. {gea_program-0.22.0 → gea_program-0.24.0}/tests/test_acceptance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gea-program
3
- Version: 0.22.0
3
+ Version: 0.24.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
@@ -125,7 +125,7 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
125
125
  gea client-report --report accuracy --out client_report
126
126
  gea model-cards --out model_cards
127
127
  gea sbom --out sbom
128
- gea accept # the product gate (353 checks)
128
+ gea accept # the product gate (359 checks)
129
129
  gea help drift # the help library, by the job (16 pages; the same text is on every dashboard page)
130
130
  gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
131
131
  gea gui # the desktop window (pip install "gea-program[desktop]")
@@ -648,6 +648,39 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
648
648
  itself; `gea help seedlink`. A TexNet station is served by EarthScope at
649
649
  `rtserve.iris.washington.edu:18000`, network `TX`.
650
650
 
651
+ ### The log as delivered, and the historian
652
+
653
+ A well log arrives as DLIS (API RP66 V1); `gea/dlis.py` reads the container
654
+ as the standard lays it out, with no dependency - the storage unit label,
655
+ visible records, logical record segments and trailers, the sets of objects
656
+ with every representation code, the frames and channels, the frame data -
657
+ and hands the strata survey the same stream the LAS port does: `gea dlis
658
+ --file log.dlis --info` describes it, `--to-las` exports a frame, `gea survey
659
+ --file log.dlis` reads it directly, and the Files page detects it by its
660
+ label. Encrypted records are skipped and named, never decrypted or guessed.
661
+ Proven on a real Schlumberger station log (104 channels, two frames, 3,252
662
+ records in a tenth of a second). The operator's gauge history in a PI System
663
+ comes out through PI Web API (`gea piwebapi`, protocol `piwebapi` on the
664
+ Patch panel): GET only, the archive between two times with its paging
665
+ followed, every value with the archive's timestamp and flags, credentials
666
+ from environment variables the map names. `gea help dlis`, `gea help
667
+ historian`.
668
+
669
+ ### The field ports
670
+
671
+ The three links a gauge panel on a pad actually offers, each read-only in
672
+ the code (no write, control, time set or device-changing command exists),
673
+ each refusing to run without the site's map and its source, each with a
674
+ stand-in on the loopback to rehearse against, each one more protocol on the
675
+ Patch panel: **Modbus RTU** (`gea modbus-rtu`; the RS-485 drop through
676
+ pyserial, the `serial` extra, or RTU over TCP through a serial-to-Ethernet
677
+ converter; CRC-16 framed and checked by this program; functions 03 and 04),
678
+ **DNP3** (`gea dnp3`; IEEE 1815 data link, transport and application layers;
679
+ integrity and event polls; analog, binary and counter objects with their
680
+ flags and 48-bit event times; confirms and unsolicited responses handled),
681
+ **HART-IP** (`gea hartip`; the session, command 0, 3 and 9; HART unit codes
682
+ converted; device and variable status to quality). `gea help field-ports`.
683
+
651
684
  ### The interval against the mapped tops
652
685
 
653
686
  Where does the injection sit in the geology? The operator declares the
@@ -86,7 +86,7 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
86
86
  gea client-report --report accuracy --out client_report
87
87
  gea model-cards --out model_cards
88
88
  gea sbom --out sbom
89
- gea accept # the product gate (353 checks)
89
+ gea accept # the product gate (359 checks)
90
90
  gea help drift # the help library, by the job (16 pages; the same text is on every dashboard page)
91
91
  gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
92
92
  gea gui # the desktop window (pip install "gea-program[desktop]")
@@ -609,6 +609,39 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
609
609
  itself; `gea help seedlink`. A TexNet station is served by EarthScope at
610
610
  `rtserve.iris.washington.edu:18000`, network `TX`.
611
611
 
612
+ ### The log as delivered, and the historian
613
+
614
+ A well log arrives as DLIS (API RP66 V1); `gea/dlis.py` reads the container
615
+ as the standard lays it out, with no dependency - the storage unit label,
616
+ visible records, logical record segments and trailers, the sets of objects
617
+ with every representation code, the frames and channels, the frame data -
618
+ and hands the strata survey the same stream the LAS port does: `gea dlis
619
+ --file log.dlis --info` describes it, `--to-las` exports a frame, `gea survey
620
+ --file log.dlis` reads it directly, and the Files page detects it by its
621
+ label. Encrypted records are skipped and named, never decrypted or guessed.
622
+ Proven on a real Schlumberger station log (104 channels, two frames, 3,252
623
+ records in a tenth of a second). The operator's gauge history in a PI System
624
+ comes out through PI Web API (`gea piwebapi`, protocol `piwebapi` on the
625
+ Patch panel): GET only, the archive between two times with its paging
626
+ followed, every value with the archive's timestamp and flags, credentials
627
+ from environment variables the map names. `gea help dlis`, `gea help
628
+ historian`.
629
+
630
+ ### The field ports
631
+
632
+ The three links a gauge panel on a pad actually offers, each read-only in
633
+ the code (no write, control, time set or device-changing command exists),
634
+ each refusing to run without the site's map and its source, each with a
635
+ stand-in on the loopback to rehearse against, each one more protocol on the
636
+ Patch panel: **Modbus RTU** (`gea modbus-rtu`; the RS-485 drop through
637
+ pyserial, the `serial` extra, or RTU over TCP through a serial-to-Ethernet
638
+ converter; CRC-16 framed and checked by this program; functions 03 and 04),
639
+ **DNP3** (`gea dnp3`; IEEE 1815 data link, transport and application layers;
640
+ integrity and event polls; analog, binary and counter objects with their
641
+ flags and 48-bit event times; confirms and unsolicited responses handled),
642
+ **HART-IP** (`gea hartip`; the session, command 0, 3 and 9; HART unit codes
643
+ converted; device and variable status to quality). `gea help field-ports`.
644
+
612
645
  ### The interval against the mapped tops
613
646
 
614
647
  Where does the injection sit in the geology? The operator declares the
@@ -123,7 +123,7 @@ from .profile_catalog import (
123
123
  read_pangaea_txt,
124
124
  )
125
125
 
126
- __version__ = "0.22.0"
126
+ __version__ = "0.24.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -278,6 +278,35 @@ def main(argv=None) -> int:
278
278
  p_lp.add_argument("--stream-csv", type=str, default=None, help="also write a historian-style CSV the other commands ingest")
279
279
  p_lp.add_argument("--selftest", action="store_true", help="etp: the codec round-trip and a session against the simulated store on the loopback")
280
280
 
281
+ p_dl = sub.add_parser("dlis", help="a DLIS (RP66 V1) well log: --info describes it (origin, channels, frames, what was skipped); --frame --out writes the frame as a historian-style CSV; --to-las writes LAS 2.0")
282
+ p_dl.add_argument("--file", type=str, required=True)
283
+ p_dl.add_argument("--info", action="store_true")
284
+ p_dl.add_argument("--frame", type=str, default=None, help="the frame to read when the file holds several")
285
+ p_dl.add_argument("--out", type=str, default=None, help="write the frame's channels as CSV (index first)")
286
+ p_dl.add_argument("--to-las", type=str, default=None, help="write the frame as a LAS 2.0 file")
287
+ p_dl.add_argument("--json", action="store_true")
288
+ p_pi = sub.add_parser("piwebapi", help="the PI Web API historian pull, read-only: --config (base_url, auth by environment variable names, tags with paths); --selftest against the stand-in")
289
+ p_pi.add_argument("--config", type=str, default=None)
290
+ p_pi.add_argument("--write-example-config", type=str, default=None)
291
+ p_pi.add_argument("--out", type=str, default=None, help="write the records CSV here")
292
+ p_pi.add_argument("--stream-csv", type=str, default=None)
293
+ p_pi.add_argument("--seconds", type=float, default=None, help="ignored: a pull is one request per tag (kept so the live tap's call shape is the same)")
294
+ p_pi.add_argument("--record", type=str, default=None, help="write the pull's summary as one JSON line here")
295
+ p_pi.add_argument("--selftest", action="store_true")
296
+ for name, helptxt in (("modbus-rtu", "Modbus RTU port, read-only: the serial line (pyserial) or RTU over TCP; functions 03/04 only; the stand-in slave with --selftest"),
297
+ ("dnp3", "DNP3 (IEEE 1815) master, read-only: integrity and event polls over TCP; analog inputs, binaries, counters with flags and event times; the stand-in outstation with --selftest"),
298
+ ("hartip", "HART-IP client, read-only: session, command 0, 3 and 9; the variables with their unit codes and status; the stand-in device with --selftest")):
299
+ p_fp = sub.add_parser(name, help=helptxt)
300
+ p_fp.add_argument("--config", type=str, default=None, help="site map JSON (client-owned): the transport, the mapping and its source")
301
+ p_fp.add_argument("--write-example-config", type=str, default=None, help="write the example map (the stand-in) here and exit")
302
+ p_fp.add_argument("--seconds", type=float, default=None, help="run for this long (polls = seconds / interval_s); default the map's polls")
303
+ p_fp.add_argument("--polls", type=int, default=None, help="poll this many times instead")
304
+ p_fp.add_argument("--record", type=str, default=None, help="write one JSON line per poll (the values and faults) here")
305
+ p_fp.add_argument("--replay", type=str, default=None, help="not offered by these ports (a poll is a request; there is nothing to replay)")
306
+ p_fp.add_argument("--out", type=str, default=None, help="write the records CSV here")
307
+ p_fp.add_argument("--stream-csv", type=str, default=None, help="also write a historian-style CSV the other commands ingest")
308
+ p_fp.add_argument("--selftest", action="store_true", help="the codec vectors and a session against the stand-in on the loopback")
309
+
281
310
  p_ws = sub.add_parser("workspace", help="the client site folder: init, add wells (file | catalogue | live), list, migrate a --out folder, refresh the dashboard, audit log")
282
311
  p_ws.add_argument("--path", type=str, required=True, help="the workspace folder")
283
312
  p_ws.add_argument("--action", type=str, default="list",
@@ -378,7 +407,7 @@ def main(argv=None) -> int:
378
407
  p_ws.add_argument("--entry", type=str, default=None, help="add-catalog: catalogue entry")
379
408
  p_ws.add_argument("--well", type=str, default=None, help="add-catalog: well tag inside the entry; remove: well id")
380
409
  p_ws.add_argument("--station-md", type=float, default=None, help="station MD in ft (catalogue wells need it)")
381
- p_ws.add_argument("--port", type=str, default=None, choices=["opcua", "mqtt", "modbus_g6"], help="add-live: the port")
410
+ p_ws.add_argument("--port", type=str, default=None, choices=["opcua", "mqtt", "modbus_g6", "wits0", "witsml", "etp", "modbus_rtu", "dnp3", "hartip"], help="add-live: the port")
382
411
  p_ws.add_argument("--from", dest="from_dir", type=str, default=None, help="migrate: a folder written by `gea dashboard --out`")
383
412
  p_ws.add_argument("--actor", type=str, default="cli", help="who is acting (recorded in the audit log)")
384
413
  p_ws.add_argument("--month", type=str, default=None, help="refresh: also measure the SLA for YYYY-MM")
@@ -657,8 +686,9 @@ def main(argv=None) -> int:
657
686
  p_fl.add_argument("--station-md", type=float, default=None)
658
687
  p_fl.add_argument("--actor", type=str, default="cli")
659
688
 
660
- p_sy = sub.add_parser("survey", help="a LAS file in, one strata report out (--demo: the bundled public KTB excerpt); --out writes report.txt + survey.json")
661
- p_sy.add_argument("--file", type=str, default=None, help="LAS 2.0 file")
689
+ p_sy = sub.add_parser("survey", help="a LAS or DLIS file in, one strata report out (--demo: the bundled public KTB excerpt); --out writes report.txt + survey.json")
690
+ p_sy.add_argument("--file", type=str, default=None, help="LAS 2.0 or DLIS (RP66 V1) file")
691
+ p_sy.add_argument("--frame", type=str, default=None, help="DLIS: the frame to read when the file holds several (gea dlis --file X --info lists them)")
662
692
  p_sy.add_argument("--demo", action="store_true")
663
693
  p_sy.add_argument("--family", type=str, default="continental_crystalline", help="prior family for the estimator")
664
694
  p_sy.add_argument("--lat", type=float, default=None)
@@ -794,8 +824,8 @@ def main(argv=None) -> int:
794
824
  import json as _json
795
825
  from .survey_cmd import run_survey
796
826
  if not (a.file or a.demo):
797
- raise SystemExit("survey needs --file <LAS> or --demo")
798
- txt, machine = run_survey(path=a.file, demo=a.demo, family=a.family, lat=a.lat, elev=a.elev)
827
+ raise SystemExit("survey needs --file <LAS or DLIS> or --demo")
828
+ txt, machine = run_survey(path=a.file, demo=a.demo, family=a.family, lat=a.lat, elev=a.elev, frame=a.frame)
799
829
  print(txt)
800
830
  if a.out:
801
831
  os.makedirs(a.out, exist_ok=True)
@@ -2268,6 +2298,175 @@ def main(argv=None) -> int:
2268
2298
  stop.set()
2269
2299
  print("etp-sim: stopped")
2270
2300
  return 0
2301
+ elif a.cmd == "dlis":
2302
+ import json as _json
2303
+ from .dlis import DlisError, DlisFile, read as _read_dlis
2304
+ try:
2305
+ if a.info or not (a.out or a.to_las):
2306
+ with open(a.file, "rb") as f:
2307
+ info = DlisFile(f.read(), os.path.basename(a.file)).describe()
2308
+ if a.json:
2309
+ print(_json.dumps(info, indent=1, default=str)); return 0
2310
+ o = info["origin"]
2311
+ print(f"dlis: {a.file}")
2312
+ print(f" storage set: {info['storage_unit']['storage_set_id']}; file {info['file_header'].get('ID', '').strip()} seq {info['file_header'].get('SEQUENCE-NUMBER', '').strip()}")
2313
+ print(f" well: {o.get('WELL-NAME', '').strip() or '?'} field: {o.get('FIELD-NAME', '').strip() or '?'} company: {o.get('COMPANY', '').strip() or '?'} producer: {o.get('PRODUCER-NAME', '').strip() or '?'} created: {o.get('CREATION-TIME', '?')}")
2314
+ print(f" {info['n_records']} logical records; sets: " + ", ".join(f"{t}{'(' + n + ')' if n else ''} x{k}" for t, n, k in info["eflr_sets"]))
2315
+ if info.get("encrypted_records"):
2316
+ print(" encrypted records skipped: " + ", ".join(f"{k} x{n}" for k, n in info["encrypted_records"].items()))
2317
+ for u in info["unparsed"]:
2318
+ print(" not parsed: " + u)
2319
+ print(f" {len(info['channels'])} channels:")
2320
+ for c in info["channels"]:
2321
+ print(f" {c['name']:<12s} {c['units']:<10s} {c['code']:<7s} dim {c['dimension']} {c['long_name']}")
2322
+ for fr in info["frames"]:
2323
+ print(f" frame {fr['name']}: index {fr['index_type']} {fr['direction']}, spacing {fr['spacing']} {fr['spacing_units']}, {fr['index_min']}..{fr['index_max']}; {len(fr['channels'])} channels: {', '.join(fr['channels'][:12])}{' ...' if len(fr['channels']) > 12 else ''}")
2324
+ return 0
2325
+ st = _read_dlis(a.file, frame=a.frame)
2326
+ except (DlisError, OSError) as e:
2327
+ raise SystemExit(f"dlis: {e}")
2328
+ print(f"dlis: frame {st.meta['frame']}: {len(st.index)} rows, index {st.meta['index_channel']} ({st.meta['index_units']}) {float(st.index[0]):g}..{float(st.index[-1]):g}, {len(st.channels)} channels"
2329
+ + (f"; {st.meta['notes']}" if st.meta.get("notes") else ""))
2330
+ if a.out:
2331
+ import csv as _csv
2332
+ with open(a.out, "w", newline="", encoding="utf-8") as f:
2333
+ w = _csv.writer(f)
2334
+ w.writerow([st.meta["index_channel"]] + list(st.channels))
2335
+ w.writerow([st.meta["index_units"]] + [st.channels[c].unit for c in st.channels])
2336
+ for i in range(len(st.index)):
2337
+ w.writerow([float(st.index[i])] + ["" if st.channels[c].values[i] != st.channels[c].values[i] else float(st.channels[c].values[i]) for c in st.channels])
2338
+ print(" csv:", a.out)
2339
+ if a.to_las:
2340
+ with open(a.to_las, "w", encoding="utf-8") as f:
2341
+ f.write("~VERSION INFORMATION\n VERS. 2.0 : CWLS LOG ASCII STANDARD - VERSION 2.0\n WRAP. NO : ONE LINE PER DEPTH STEP\n")
2342
+ f.write("~WELL INFORMATION\n")
2343
+ f.write(f" STRT.{st.meta['index_units']:<6s} {float(st.index[0]):.4f} : START\n STOP.{st.meta['index_units']:<6s} {float(st.index[-1]):.4f} : STOP\n")
2344
+ f.write(f" STEP.{st.meta['index_units']:<6s} {(float(st.index[1]) - float(st.index[0])) if len(st.index) > 1 else 0.0:.4f} : STEP\n NULL. -999.25 : NULL VALUE\n")
2345
+ f.write(f" WELL. {st.meta.get('WELL-NAME', '').strip()} : WELL\n FLD . {st.meta.get('FIELD-NAME', '').strip()} : FIELD\n COMP. {st.meta.get('COMPANY', '').strip()} : COMPANY\n SRVC. {st.meta.get('PRODUCER-NAME', '').strip()} : SERVICE COMPANY\n")
2346
+ f.write(f" SRC . DLIS {os.path.basename(a.file)} frame {st.meta['frame']} : SOURCE (gea dlis --to-las)\n")
2347
+ f.write("~CURVE INFORMATION\n")
2348
+ f.write(f" {st.meta['index_channel']:<8s}.{st.meta['index_units']:<8s} : INDEX\n")
2349
+ for c in st.channels:
2350
+ f.write(f" {c:<8s}.{st.channels[c].unit:<8s} : {c}\n")
2351
+ f.write("~A\n")
2352
+ for i in range(len(st.index)):
2353
+ f.write(f"{float(st.index[i]):.4f}" + "".join(f" {(-999.25 if st.channels[c].values[i] != st.channels[c].values[i] else float(st.channels[c].values[i])):.4f}" for c in st.channels) + "\n")
2354
+ print(" las:", a.to_las)
2355
+ return 0
2356
+ elif a.cmd == "piwebapi":
2357
+ import json as _json
2358
+ from .live_ports import records_to_stream, summarize, write_records_csv
2359
+ from . import piwebapi as _PI
2360
+ if a.selftest:
2361
+ r = _PI.selftest()
2362
+ print(f"piwebapi selftest: {'OK' if r['ok'] else 'FAILED'}")
2363
+ for k, v in r.items():
2364
+ if k != "ok":
2365
+ print(f" {'ok ' if v else 'BAD'} {k}")
2366
+ return 0 if r["ok"] else 1
2367
+ if a.write_example_config:
2368
+ with open(a.write_example_config, "w", encoding="utf-8") as f:
2369
+ _json.dump(_PI.EXAMPLE_CONFIG, f, indent=1)
2370
+ print("config:", a.write_example_config); return 0
2371
+ if not a.config:
2372
+ raise SystemExit("piwebapi needs --config (or --write-example-config to start one)")
2373
+ cfg = _PI.load_config(a.config)
2374
+ sim_h = None
2375
+ try:
2376
+ if cfg.get("base_url") == "sim":
2377
+ sim = _PI.SimServer(); sim_h, port_ = sim.serve(); cfg = {**cfg, "base_url": f"http://127.0.0.1:{port_}/piwebapi", "auth": "none"}
2378
+ try:
2379
+ port = _PI.PiPort(cfg)
2380
+ r = port.pull()
2381
+ except (_PI.PiError, ValueError) as e:
2382
+ raise SystemExit(f"piwebapi: {e}")
2383
+ finally:
2384
+ if sim_h is not None:
2385
+ sim_h.close()
2386
+ recs = port.records
2387
+ print(f"piwebapi: {_json.dumps(port.summary(), default=str)}")
2388
+ print(_json.dumps(summarize(recs), indent=1))
2389
+ if a.record:
2390
+ with open(a.record, "w", encoding="utf-8") as f:
2391
+ f.write(_json.dumps({"pull": r, "summary": port.summary()}, default=str) + "\n")
2392
+ if a.out:
2393
+ print(" records:", write_records_csv(recs, a.out))
2394
+ if a.stream_csv and recs:
2395
+ st = records_to_stream(recs, name="piwebapi")
2396
+ import csv as _csv
2397
+ from datetime import datetime as _dt, timedelta as _td
2398
+ t0 = _dt.fromisoformat(st.meta["start_time"])
2399
+ with open(a.stream_csv, "w", newline="", encoding="utf-8") as f:
2400
+ w = _csv.writer(f)
2401
+ w.writerow(["timestamp"] + list(st.channels))
2402
+ for i, t in enumerate(st.index):
2403
+ 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])
2404
+ print(" stream:", a.stream_csv)
2405
+ return 0 if not port.faults else 1
2406
+ elif a.cmd in ("modbus-rtu", "dnp3", "hartip"):
2407
+ import json as _json
2408
+ from .live_ports import records_to_stream, summarize, write_records_csv
2409
+ mod = __import__({"modbus-rtu": "gea.modbus_rtu", "dnp3": "gea.dnp3", "hartip": "gea.hartip"}[a.cmd], fromlist=["x"])
2410
+ if a.selftest:
2411
+ r = mod.selftest()
2412
+ print(f"{a.cmd} selftest: {'OK' if r['ok'] else 'FAILED'}")
2413
+ for k, v in r.items():
2414
+ if k != "ok":
2415
+ print(f" {'ok ' if v else 'BAD'} {k}")
2416
+ return 0 if r["ok"] else 1
2417
+ if a.write_example_config:
2418
+ with open(a.write_example_config, "w", encoding="utf-8") as f:
2419
+ _json.dump(mod.EXAMPLE_CONFIG, f, indent=1)
2420
+ print("config:", a.write_example_config); return 0
2421
+ if a.replay:
2422
+ raise SystemExit(f"{a.cmd}: a poll is a request to the device; there is no recording to replay - run against the device or the stand-in")
2423
+ if not a.config:
2424
+ raise SystemExit(f"{a.cmd} needs --config (or --write-example-config to start one)")
2425
+ cfg = mod.load_config(a.config)
2426
+ polls = a.polls
2427
+ if polls is None and a.seconds is not None:
2428
+ polls = max(1, int(round(a.seconds / max(float(cfg.get("interval_s", 1.0)), 0.05))))
2429
+ from .patches import close_field_port, open_field_port
2430
+ proto = {"modbus-rtu": "modbus_rtu", "dnp3": "dnp3", "hartip": "hartip"}[a.cmd]
2431
+ try:
2432
+ tap = open_field_port(proto, mod, cfg)
2433
+ except (NotImplementedError, ConnectionError, ValueError, OSError) as e:
2434
+ raise SystemExit(f"{a.cmd}: {e}")
2435
+ rec_f = open(a.record, "w", encoding="utf-8") if a.record else None
2436
+ n = int(cfg.get("polls", 3) if polls is None else polls)
2437
+ dt = float(cfg.get("interval_s", 1.0))
2438
+ try:
2439
+ for k in range(n):
2440
+ before = len(tap.records)
2441
+ r = tap.poll_once(integrity=(k == 0)) if a.cmd == "dnp3" else tap.poll_once()
2442
+ if rec_f:
2443
+ rec_f.write(_json.dumps({"poll": k + 1, "utc": tap.records[-1].ingest_timestamp_utc if tap.records else None,
2444
+ "values": {x.tag_id: x.value for x in tap.records[before:]}, "quality": {x.tag_id: x.quality_flag for x in tap.records[before:]},
2445
+ "detail": (r if isinstance(r, dict) and a.cmd != "modbus-rtu" else None)}, default=str) + "\n")
2446
+ if dt > 0 and k < n - 1:
2447
+ import time as _time
2448
+ _time.sleep(dt)
2449
+ finally:
2450
+ close_field_port(proto, tap)
2451
+ if rec_f:
2452
+ rec_f.close()
2453
+ recs = tap.records
2454
+ print(f"{a.cmd}: {_json.dumps(tap.summary(), default=str)}")
2455
+ print(_json.dumps(summarize(recs), indent=1))
2456
+ if a.out:
2457
+ print(" records:", write_records_csv(recs, a.out))
2458
+ if a.stream_csv and recs:
2459
+ st = records_to_stream(recs, name=proto)
2460
+ import csv as _csv
2461
+ from datetime import datetime as _dt, timedelta as _td
2462
+ t0 = _dt.fromisoformat(st.meta["start_time"])
2463
+ with open(a.stream_csv, "w", newline="", encoding="utf-8") as f:
2464
+ w = _csv.writer(f)
2465
+ w.writerow(["timestamp"] + list(st.channels))
2466
+ for i, t in enumerate(st.index):
2467
+ 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])
2468
+ print(" stream:", a.stream_csv)
2469
+ return 0
2271
2470
  elif a.cmd in ("opcua", "mqtt", "wits0", "witsml", "etp"):
2272
2471
  import json as _json
2273
2472
  from .live_ports import records_to_stream, summarize, write_records_csv