gateway_api.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. from __future__ import annotations
  2. from typing import Any
  3. from .auth import find_project_config
  4. from .http_client import request_json
  5. from .protocols import BACNET_SPEC, MODBUS_SPEC, S7_SPEC
  6. from .protocols.bacnet import normalize_bacnet_object_type
  7. def _request_gateway(project_key: str, path: str | None, payload: dict[str, Any] | None, protocol: str) -> dict[str, Any]:
  8. project = find_project_config(project_key)
  9. if not path:
  10. raise ValueError(f"{protocol} gateway path is not configured")
  11. response_payload = request_json(
  12. "POST",
  13. f"{project['base_url']}{path}",
  14. json_payload=payload,
  15. )
  16. if not isinstance(response_payload, dict):
  17. raise ValueError(f"gateway API returned invalid payload: {response_payload}")
  18. return response_payload
  19. def modbus_point_collect_test(
  20. project_key: str,
  21. *,
  22. ip: str,
  23. port: int,
  24. slave_id: int,
  25. points: list[dict[str, Any]],
  26. device_type: str = "ModbusTCP",
  27. word_byte_order: str = "ABCD",
  28. address_base: int = 0,
  29. ) -> dict[str, Any]:
  30. payload = {
  31. "device_type": device_type,
  32. "ip": ip,
  33. "port": port,
  34. "word_byte_order": word_byte_order,
  35. "address_base": address_base,
  36. "slave_id": slave_id,
  37. "points": points,
  38. }
  39. return _request_gateway(project_key, MODBUS_SPEC.point_test_path, payload, "modbus point test")
  40. def modbus_raw_read(
  41. project_key: str,
  42. *,
  43. ip: str,
  44. port: int,
  45. slave_id: int,
  46. read: dict[str, Any],
  47. device_type: str = "ModbusTCP",
  48. word_byte_order: str = "ABCD",
  49. address_base: int = 0,
  50. ) -> dict[str, Any]:
  51. payload = {
  52. "device_type": device_type,
  53. "ip": ip,
  54. "port": port,
  55. "word_byte_order": word_byte_order,
  56. "address_base": address_base,
  57. "slave_id": slave_id,
  58. "read": read,
  59. }
  60. return _request_gateway(project_key, MODBUS_SPEC.raw_read_path, payload, "modbus raw read")
  61. def bacnet_point_collect_test(
  62. project_key: str,
  63. *,
  64. ip: str,
  65. bacnet_device_id: int,
  66. points: list[dict[str, Any]],
  67. port: int = 47808,
  68. ) -> dict[str, Any]:
  69. normalized_points = []
  70. for point in points:
  71. normalized_point = dict(point)
  72. normalized_point["object_type"] = normalize_bacnet_object_type(normalized_point.get("object_type"))
  73. normalized_points.append(normalized_point)
  74. payload = {
  75. "ip": ip,
  76. "bacnet_device_id": bacnet_device_id,
  77. "port": port,
  78. "points": normalized_points,
  79. }
  80. return _request_gateway(project_key, BACNET_SPEC.point_test_path, payload, "bacnet point test")
  81. def bacnet_point_search(
  82. project_key: str,
  83. *,
  84. ip: str,
  85. bacnet_device_id: int,
  86. port: int = 47808,
  87. ) -> dict[str, Any]:
  88. payload = {
  89. "ip": ip,
  90. "bacnet_device_id": bacnet_device_id,
  91. "port": port,
  92. }
  93. return _request_gateway(project_key, BACNET_SPEC.search_points_path, payload, "bacnet point search")
  94. def bacnet_bbmd_whois(project_key: str) -> dict[str, Any]:
  95. return _request_gateway(project_key, BACNET_SPEC.bbmd_whois_path, None, "bacnet bbmd whois")
  96. def s7_raw_read(
  97. project_key: str,
  98. *,
  99. ip: str,
  100. rock: int,
  101. slot: int,
  102. read: dict[str, Any],
  103. device_type: str = "S7-1200",
  104. port: int = 102,
  105. tsap_conn_type: str | None = None,
  106. ) -> dict[str, Any]:
  107. payload = {
  108. "device_type": device_type,
  109. "ip": ip,
  110. "port": port,
  111. "rock": rock,
  112. "slot": slot,
  113. "tsap_conn_type": _resolve_s7_tsap_conn_type(device_type, tsap_conn_type),
  114. "read": read,
  115. }
  116. return _request_gateway(project_key, S7_SPEC.raw_read_path, payload, "s7 raw read")
  117. def s7_point_collect_test(
  118. project_key: str,
  119. *,
  120. ip: str,
  121. rock: int,
  122. slot: int,
  123. points: list[dict[str, Any]],
  124. device_type: str = "S7-1200",
  125. port: int = 102,
  126. tsap_conn_type: str | None = None,
  127. ) -> dict[str, Any]:
  128. payload = {
  129. "device_type": device_type,
  130. "ip": ip,
  131. "port": port,
  132. "rock": rock,
  133. "slot": slot,
  134. "tsap_conn_type": _resolve_s7_tsap_conn_type(device_type, tsap_conn_type),
  135. "points": points,
  136. }
  137. return _request_gateway(project_key, S7_SPEC.point_test_path, payload, "s7 point test")
  138. def s7_connect_scan(project_key: str, *, ip: str) -> dict[str, Any]:
  139. return _request_gateway(project_key, S7_SPEC.connect_scan_path, {"ip": ip}, "s7 connect scan")
  140. def _resolve_s7_tsap_conn_type(device_type: str, tsap_conn_type: str | None) -> str:
  141. normalized_tsap = str(tsap_conn_type or "").strip().upper()
  142. if normalized_tsap:
  143. return normalized_tsap
  144. return "PG"