liuxingchen 1 سال پیش
والد
کامیت
1cfbb4459a
100فایلهای تغییر یافته به همراه7710 افزوده شده و 0 حذف شده
  1. 7 0
      005_H570/jikong_script/abstract_api.py
  2. 135 0
      005_H570/jikong_script/alarm.py
  3. 117 0
      005_H570/jikong_script/alarm_buzzer.py
  4. 136 0
      005_H570/jikong_script/alarm_record.py
  5. 9 0
      005_H570/jikong_script/api_context.py
  6. 27 0
      005_H570/jikong_script/apis/add_user_operation.py
  7. 33 0
      005_H570/jikong_script/apis/alarm_change_limit.py
  8. 56 0
      005_H570/jikong_script/apis/alarm_close_buzzer.py
  9. 82 0
      005_H570/jikong_script/apis/alarm_get_data.py
  10. 32 0
      005_H570/jikong_script/apis/alarm_get_point_config.py
  11. 36 0
      005_H570/jikong_script/apis/alarm_link_buzzer.py
  12. 56 0
      005_H570/jikong_script/apis/api_init.py
  13. 30 0
      005_H570/jikong_script/apis/cancel_alarm.py
  14. 31 0
      005_H570/jikong_script/apis/cancel_moxa_e1210_alarm.py
  15. 28 0
      005_H570/jikong_script/apis/change_alarm_limit.py
  16. 41 0
      005_H570/jikong_script/apis/change_auto_feed_info.py
  17. 32 0
      005_H570/jikong_script/apis/change_auto_switch_device.py
  18. 39 0
      005_H570/jikong_script/apis/change_laliji_param.py
  19. 43 0
      005_H570/jikong_script/apis/change_maintenance_info.py
  20. 44 0
      005_H570/jikong_script/apis/change_touer_info.py
  21. 29 0
      005_H570/jikong_script/apis/change_underwater_equip_clean_cycle.py
  22. 27 0
      005_H570/jikong_script/apis/change_wind_light_config.py
  23. 33 0
      005_H570/jikong_script/apis/del_user_operation.py
  24. 218 0
      005_H570/jikong_script/apis/electric_mangement.py
  25. 39 0
      005_H570/jikong_script/apis/flow_direction_radar_chart.py
  26. 47 0
      005_H570/jikong_script/apis/gather_fish_light_change_mode.py
  27. 51 0
      005_H570/jikong_script/apis/gather_fish_light_get_mode.py
  28. 70 0
      005_H570/jikong_script/apis/get_alarm_info.py
  29. 46 0
      005_H570/jikong_script/apis/get_auto_feed_info.py
  30. 22 0
      005_H570/jikong_script/apis/get_auto_switch_device.py
  31. 30 0
      005_H570/jikong_script/apis/get_avg_data.py
  32. 72 0
      005_H570/jikong_script/apis/get_each_depth_data.py
  33. 41 0
      005_H570/jikong_script/apis/get_extreme_wind_speed.py
  34. 51 0
      005_H570/jikong_script/apis/get_feeding_advise.py
  35. 35 0
      005_H570/jikong_script/apis/get_feeding_amount.py
  36. 63 0
      005_H570/jikong_script/apis/get_feeding_curve.py
  37. 41 0
      005_H570/jikong_script/apis/get_fishery_data_all.py
  38. 25 0
      005_H570/jikong_script/apis/get_fishery_data_detail.py
  39. 79 0
      005_H570/jikong_script/apis/get_historical_data.py
  40. 78 0
      005_H570/jikong_script/apis/get_history_curve_data.py
  41. 81 0
      005_H570/jikong_script/apis/get_history_form_data.py
  42. 80 0
      005_H570/jikong_script/apis/get_last_time_feeding_data.py
  43. 32 0
      005_H570/jikong_script/apis/get_maintenance_info.py
  44. 29 0
      005_H570/jikong_script/apis/get_max_data.py
  45. 55 0
      005_H570/jikong_script/apis/get_maximum_wind_speed.py
  46. 28 0
      005_H570/jikong_script/apis/get_min_data.py
  47. 38 0
      005_H570/jikong_script/apis/get_moxa_e1210_alarm.py
  48. 33 0
      005_H570/jikong_script/apis/get_touer_info.py
  49. 40 0
      005_H570/jikong_script/apis/get_underwater_equip_clean_info.py
  50. 31 0
      005_H570/jikong_script/apis/get_unread_alarm.py
  51. 46 0
      005_H570/jikong_script/apis/get_user_operation.py
  52. 47 0
      005_H570/jikong_script/apis/get_weather_history_data.py
  53. 73 0
      005_H570/jikong_script/apis/operate_mysql.py
  54. 30 0
      005_H570/jikong_script/apis/read_point_info.py
  55. 21 0
      005_H570/jikong_script/apis/read_wind_light_config.py
  56. 24 0
      005_H570/jikong_script/apis/reset_device_run_time.py
  57. 26 0
      005_H570/jikong_script/apis/reset_total_feed_select_time.py
  58. 36 0
      005_H570/jikong_script/apis/robot_get_all_date.py
  59. 32 0
      005_H570/jikong_script/apis/robot_get_history_position_data.py
  60. 30 0
      005_H570/jikong_script/apis/robot_real_data.py
  61. 43 0
      005_H570/jikong_script/apis/update_underwater_equip_clean_time.py
  62. 44 0
      005_H570/jikong_script/apis/yuntaideng_change_mode.py
  63. 31 0
      005_H570/jikong_script/apis/yuntaideng_get_mode.py
  64. 86 0
      005_H570/jikong_script/auto_charge.py
  65. 313 0
      005_H570/jikong_script/auto_feeding.py
  66. 84 0
      005_H570/jikong_script/auto_profile_1501.py
  67. 126 0
      005_H570/jikong_script/auto_switch_device.py
  68. 266 0
      005_H570/jikong_script/auto_switch_juyudeng.py
  69. 112 0
      005_H570/jikong_script/auto_switch_yuntaideng.py
  70. 18 0
      005_H570/jikong_script/config.json
  71. 32 0
      005_H570/jikong_script/configuration.py
  72. 31 0
      005_H570/jikong_script/connector.py
  73. 10 0
      005_H570/jikong_script/connectors/__init__.py
  74. 341 0
      005_H570/jikong_script/connectors/gather_fish_light_connector.py
  75. 83 0
      005_H570/jikong_script/connectors/http_connector.py
  76. 170 0
      005_H570/jikong_script/connectors/melsec_plc_a1e_connector.py
  77. 175 0
      005_H570/jikong_script/connectors/modbus_moxae1210_connector.py
  78. 194 0
      005_H570/jikong_script/connectors/modbus_rtu_over_tcp_connector.py
  79. 226 0
      005_H570/jikong_script/connectors/modbus_rtu_over_tcp_normal.py
  80. 210 0
      005_H570/jikong_script/connectors/modbus_tcp_connector.py
  81. 192 0
      005_H570/jikong_script/connectors/siemens_plc_s7_connector.py
  82. 192 0
      005_H570/jikong_script/connectors/siemens_plc_s7_s200smart_connector.py
  83. 222 0
      005_H570/jikong_script/connectors/tcp_connector.py
  84. 8 0
      005_H570/jikong_script/converter.py
  85. 6 0
      005_H570/jikong_script/converters/__init__.py
  86. 42 0
      005_H570/jikong_script/converters/a1e_converter.py
  87. 149 0
      005_H570/jikong_script/converters/modbus_converter.py
  88. 9 0
      005_H570/jikong_script/converters/pass_converter.py
  89. 73 0
      005_H570/jikong_script/converters/s7_converter.py
  90. 30 0
      005_H570/jikong_script/converters/shucai_converter.py
  91. 122 0
      005_H570/jikong_script/converters/tcp_converter.py
  92. 71 0
      005_H570/jikong_script/creat_tbl.py
  93. 77 0
      005_H570/jikong_script/event_storage.py
  94. 150 0
      005_H570/jikong_script/feeding_statistics.py
  95. 260 0
      005_H570/jikong_script/gateway.py
  96. 89 0
      005_H570/jikong_script/gateway_read_conn.py
  97. 80 0
      005_H570/jikong_script/gateway_web.py
  98. 48 0
      005_H570/jikong_script/get_laliji_param.py
  99. 291 0
      005_H570/jikong_script/hard_disk_storage.py
  100. 81 0
      005_H570/jikong_script/historical_data_storage.py

+ 7 - 0
005_H570/jikong_script/abstract_api.py

@@ -0,0 +1,7 @@
+from abc import ABC, abstractmethod
+
+class AbstractApi(ABC):
+
+    @abstractmethod
+    def operation(self, request):
+        pass

+ 135 - 0
005_H570/jikong_script/alarm.py

@@ -0,0 +1,135 @@
+import time
+from event_storage import EventStorage
+from log import OutPutLog
+from datetime import datetime, timedelta
+
+
+class Alarm:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._save_frequency = 5
+        self._last_save_time = 0
+        self._log = OutPutLog()
+
+    def get_real_time_data(self):
+        """
+        :return: data_dict {'c1': '064', 'c2': '0.1', 'c3': '20.3', 'c4': '43.2', 'c5': '1025.1', 'c6': '0.25', 'c81': '29.823', 'c82': '104.507', 'c83': '253.153'...}
+        """
+        point_info = self._storage.hardDiskStorage.get_point_info(point_tuple=None)
+        # print(point_info)
+        keys_list = []
+        for index in point_info:
+            keys_list.append('c' + str(index['serial_number']))
+        data_dict = self._storage.memoryStorage.get_value(keys_list)
+        # print(data_dict)
+        return data_dict
+
+    def get_point_table(self):
+        """
+        获取所有点的点表,并增加alarm_status属性
+        :return: point_info 字典组成的列表
+        """
+        point_info = self._storage.hardDiskStorage.get_point_info(point_tuple=None)
+        for obj in point_info:
+            obj['alarm_status'] = 0
+        return point_info
+
+    def update_point_table(self, point_info):
+        """
+        更新点表,主要更新报警上限和报警下限
+        :param point_info: 更新前的点表
+        :return: 更新后的点表
+        """
+        new = self._storage.hardDiskStorage.get_point_info(point_tuple=None)
+        for i in range(0, len(new)):
+            point_info[i]['alarm_low_limit'] = new[i]['alarm_low_limit']
+            point_info[i]['alarm_up_limit'] = new[i]['alarm_up_limit']
+
+    # 越限报警
+    def overrun_alarm(self):
+        self._log.info('[overrun_alarm] - Over run alarm module is running!')
+        try:
+            point_info = self.get_point_table()
+            while 1:
+                self.update_point_table(point_info)
+                # print(time.time(), point_info[0]['alarm_low_limit'], point_info[0]['alarm_up_limit'])
+                data_dict = self.get_real_time_data()
+                # print(data_dict['c1'])
+                for index in point_info:
+                    key = 'c' + str(index['serial_number'])
+                    # print('addr = ', addr, 'addr type = ', type(addr))
+                    if data_dict[key]:  # 数据不为空且报警状态为零
+                        data_dict[key] = float(data_dict[key])
+                        if index['alarm_low_limit'] is None or index['alarm_up_limit'] is None:  # 未设置报警限值
+                            continue
+                        elif index['alarm_low_limit'] <= data_dict[key] <= index['alarm_up_limit']:  # 在合理范围内
+                            index['alarm_status'] = 0
+                        else:  # 数据越限
+                            if index['alarm_status'] == 0:  # alarm_status == 0:表示第一次报警,存储报警信息
+                                alarm_unit = {'name': "'" + key + "'", 'data': data_dict[key]}
+                                table_name = "alarm_data_tbl"  # 报警存储表名,可以通过配置文件配置
+                                alarm_time = time.strftime("%Y-%m-%d %H:%M:%S")
+                                self._log.debug('[overrun_alarm] - ' + repr(alarm_unit))
+                                self._storage.hardDiskStorage.insert_column_many(table_name, alarm_time, alarm_unit)
+                                index['alarm_status'] = 1
+                            elif index['alarm_status'] == 1:  # alarm_status == 1:表示本次报警期间非第一次检测的越限
+                                continue
+                time.sleep(1)
+        except Exception as e:
+            msg = str(time.strftime("%Y-%m-%d %H:%M:%M"))
+            print(f'{msg}: error in overrun_alarm: {e}')
+
+    def overrun_alarm_storage(self, table_name, save_time, item):
+        pass
+
+    # 变位报警
+    def displacement_alarm(self):
+        self._log.info('[displacement_alarm] - Displacement alarm module is running!')
+        point_info = self._storage.hardDiskStorage.get_point_info(point_tuple=None)
+
+        keys_list = []
+        for index in point_info:
+            keys_list.append('c' + str(index['serial_number']))
+        last_data_dict = self._storage.memoryStorage.get_value(keys_list)
+
+        while 1:
+            now_data_dict = self._storage.memoryStorage.get_value(keys_list)
+            # print(now_data_dict)
+            for index in point_info:
+                key = 'c' + str(index['serial_number'])
+                if index['signal_type'] == 'Switch' and now_data_dict[key]:
+                    if now_data_dict[key] != last_data_dict[key]:
+                        self._log.info(repr(now_data_dict[key]) + repr(last_data_dict[key]))
+                    else:
+                        pass
+            last_data_dict = now_data_dict
+            self._log.info(last_data_dict)
+            time.sleep(1)
+
+    def displacement_alarm_storage(self):
+        pass
+
+
+    def moxa_e1210_alarm(self):
+        """开关量综合报警的提示"""
+        point_list = ["c365", "c367", "c368", "c371", "c372", "c373", "c374", "c375", "c376", "c377"]
+        real_data_dict = self._storage.get_real_data(point_list)
+        # real_data_dict = {'c365': '0', 'c367': '0', 'c368': '1', 'c371': '0', 'c372': '0', 'c373': '0', 'c374': '0', 'c375': '0', 'c376': '1', 'c377': '0'}
+        alarm_time = datetime.now()
+        alarm_time_limit = (alarm_time+timedelta(minutes=-30)).strftime("%Y-%m-%d %H:%M:%S")
+        
+        for serial_number,value in real_data_dict.items():
+            if value and int(value) == 1:
+                select_sql = f"SELECT serial_number FROM alarm_moxa_e1210 WHERE serial_number=\'{serial_number}\' AND update_time>\'{alarm_time_limit}\';"
+                if not self._storage.execute_sql(select_sql):
+                    insert_sql = f"INSERT INTO alarm_moxa_e1210 (`create_time`, `update_time`, `serial_number`) VALUES (\'{alarm_time}\', \'{alarm_time}\', \'{serial_number}\');"
+                    self._storage.execute_update_sql(insert_sql)
+                else:
+                    update_sql = f"UPDATE alarm_moxa_e1210 SET update_time=\'{alarm_time}\' WHERE serial_number=\'{serial_number}\' AND update_time>\'{alarm_time_limit}\';"
+                    self._storage.execute_update_sql(update_sql)
+        
+
+
+if __name__ == '__main__':
+    alarm = Alarm()
+    alarm.overrun_alarm()

+ 117 - 0
005_H570/jikong_script/alarm_buzzer.py

@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/16 10:48
+@Author: lxc
+@LastEditTime: 
+@Desctiption:根据数据表存储的报警,判断蜂鸣器是否需要报警
+"""
+
+from event_storage import EventStorage
+from log import OutPutLog
+import time
+from datetime import datetime
+from utility import Utility
+
+
+class AlarmBuzzer:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+
+    def run(self):
+
+        run_time = 0
+        while True:
+            this_time = time.time()
+            if this_time - run_time >5:
+                run_time = this_time
+
+                self.judge_buzzer_alarm()
+
+
+    def judge_buzzer_alarm(self):
+        # 蜂鸣器状态:c809
+        read_real_list = ["c809"]
+        real_data_dict = self._storage.get_real_data(read_real_list)
+        buzzer_status = real_data_dict["c809"]          # 蜂鸣器当前状态,0:蜂鸣器关闭,1:蜂鸣器开启
+        if buzzer_status is not None:
+            buzzer_status = int(buzzer_status)
+
+        get_set_buzzer_status = "SELECT buzzer_status FROM `alarm_set`;"
+        set_buzzer_status = self._storage.execute_sql(get_set_buzzer_status)    # 是否开启蜂鸣器报警功能,0=关闭,1=开启
+        # print("-------------------", set_buzzer_status)
+
+        if set_buzzer_status[0]["buzzer_status"] == 1:
+            # 判断是否有报警点,如果有,则蜂鸣器报警
+            get_alarm_sql = "SELECT id,CAST(create_time AS CHAR) AS create_time,CAST(update_time AS CHAR) AS update_time,point_name,data,buzzer_status_time,signal_type FROM alarm_tbl WHERE is_cancel=0;"
+            alarm_data = self._storage.execute_sql(get_alarm_sql)
+
+            if alarm_data:
+                buzzer_status_time = alarm_data[0]["buzzer_status_time"]
+                self.now_time = datetime.now()
+
+                if buzzer_status is None or buzzer_status_time is None:
+                    # turn on the buzzer
+                    if self.send_command("open"):
+                        self.update_alarm_tbl()
+                    else:
+                        print("turn on the buzzer failed!")
+
+                else:
+                    # 计算蜂鸣器保持开启或关闭状态的时长
+                    buzzer_hold_time = (self.now_time - buzzer_status_time).total_seconds()
+                    if buzzer_status == 0 and buzzer_hold_time > 60 * 10:
+                        # buzzer off and turn on the buzzer
+                        if self.send_command("open"):
+                            self.update_alarm_tbl()
+                        else:
+                            print("turn on the buzzer failed!")
+
+                    elif buzzer_status == 1 and buzzer_hold_time > 60 * 3:
+                        # buzzer on and turn off the buzzer
+                        if self.send_command("close"):
+                            self.update_alarm_tbl()
+                        else:
+                            print("turn off the buzzer failed!")
+            elif buzzer_status == 1:
+                # 没有报警点 判断蜂鸣器状态 如果蜂鸣器在响 关掉蜂鸣器
+                if self.send_command("close"):
+                    print("turn off the buzzer success!")
+                else:
+                    print("turn off the buzzer failed!")
+
+
+        elif buzzer_status == 1:
+            # 无论是否有报警,都关闭蜂鸣器
+            if self.send_command("close"):
+                print("turn off the buzzer success!")
+            else:
+                print("turn off the buzzer failed!")
+
+
+
+    def send_command(self, status):
+        '''给蜂鸣器发送指令,并更新数据库'''
+        if status == "open":
+            # turn on the buzzer
+            command = {"device_id": 1, "start_addr": 0, "output_value": 65280, "function_code": 5, "res": 65280}
+        elif status == "close":
+            # turn off the buzzer
+            command = {"device_id": 1, "start_addr": 0, "output_value": 0, "function_code": 5, "res": 0}
+        elif status == "status":
+            # views the buzzer status
+            command = {"device_id": 1, "start_addr": 0, "length": 1, "function_code": 1}
+
+        station_name = "buzzer"
+        commend_result = Utility.available_connectors[station_name].send_command(command)
+        return commend_result
+
+
+    def update_alarm_tbl(self):
+        '''更新数据库的报警信息'''
+        update_sql = f"UPDATE alarm_tbl SET buzzer_status_time=\'{self.now_time}\' WHERE is_cancel=0;"
+        update_result = self._storage.execute_update_sql(update_sql)
+        # print(update_result)
+        return update_result
+

+ 136 - 0
005_H570/jikong_script/alarm_record.py

@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/16 17:20
+@Author: lxc
+@LastEditTime: 
+@Desctiption:判断接入集控系统的所有设备的参数的实时值是否异常,并记录
+"""
+
+import time
+from event_storage import EventStorage
+from log import OutPutLog
+from datetime import datetime
+
+class AlarmRecord:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+
+
+    def run(self):
+        run_time = 0
+        while True:
+            this_time = time.time()
+            if this_time - run_time > 10:
+                run_time = this_time
+                self.now_time = datetime.now()
+                self.deal_alarm()
+
+
+
+    def deal_alarm(self):
+
+        # 查询已经存在的报警参数信息
+        alarm_point_dict = self.get_alarm_tbl()
+        # 查看点表中,所有需要判断是否需要报警的点
+        point_list, point_dict = self.get_buzzer_alarm_point()
+        # 读取实时数据
+        last_data_dict = self.get_real_data(point_list)
+
+
+        for serial_number, value in last_data_dict.items():
+            try:
+                # 区分参数类型:Switch、Analog、device_clean
+                if serial_number.startswith("c"):
+                    signal_type = point_dict[serial_number][0]
+                else:
+                    signal_type = "device_clean"
+
+                # 判断该参数的值是否正常
+                alarm_status = 0      # 默认该参数的数值正常。0:正常,1:异常
+                if value is None:
+                    # alarm_status = 1
+                    pass
+                else:
+                    if signal_type == "Switch":
+                        alarm_status = int(value)
+                    elif signal_type == "Analog":
+                        alarm_low_limit = point_dict[serial_number][1]
+                        alarm_up_limit = point_dict[serial_number][2]
+                        if alarm_low_limit is not None and alarm_up_limit is not None:
+                            alarm_status = 0 if float(alarm_low_limit) <= float(value) <= float(alarm_up_limit) else 1
+                    elif signal_type == "device_clean" and value < self.now_time:
+                        alarm_status = 1
+                        value = None
+
+                    # print(serial_number, alarm_status)
+
+
+                # 更新到数据库
+                if serial_number in alarm_point_dict.keys():
+                    # 该参数的报警已经存在,更新alarm_tbl表的update_time、alarm_point_status字段
+                    alarm_id = alarm_point_dict[serial_number]
+                    if alarm_status == 1:
+                        update_sql = f"UPDATE `alarm_tbl` SET `update_time`=\'{self.now_time}\', `alarm_point_status`=0 WHERE `id`={alarm_id};"
+                    elif alarm_status == 0:
+                        update_sql = f"UPDATE `alarm_tbl` SET `update_time`=\'{self.now_time}\', `alarm_point_status`=1, `is_cancel`=1 WHERE `id`={alarm_id};"
+
+                    update_result = self._storage.execute_update_sql(update_sql)
+                    # print(update_result, update_sql)
+                    # self._log.info([update_result, update_sql])
+
+                elif alarm_status == 1:
+                    # 产生新的报警点,alarm_tbl表插入一条新的报警数据
+                    insert_sql = f"INSERT INTO `alarm_tbl` SET `point_name`=\'{serial_number}\',`data`={value}, `signal_type`=\'{signal_type}\';"
+                    insert_sql = insert_sql.replace("None", "NULL")
+                    insert_result = self._storage.execute_update_sql(insert_sql)
+                    # print(insert_result, insert_sql)
+                    # self._log.info([insert_result, insert_sql])
+
+            except Exception as e:
+                print(f"[AlarmAll]: {e}")
+                self._log.error(e)
+
+
+    def get_alarm_tbl(self):
+        """
+        查询已经存在的报警信息
+        :return: {'c14': 2, 'c12': 1, 'c369': 9, 'c373': 12, 'c375': 13, ...}
+        """
+        alarm_sql = f"SELECT id,point_name FROM alarm_tbl WHERE alarm_point_status=0;"
+        alarm_info = self._storage.execute_sql(alarm_sql)
+        alarm_point_dict = {}
+        for each_alarm in alarm_info:
+            alarm_point_dict[each_alarm["point_name"]] = each_alarm["id"]
+        return alarm_point_dict
+
+
+    def get_buzzer_alarm_point(self):
+        """
+        # 查看点表和水下设备清洗配置表中,所有需要判断是否需要报警的点
+        :return:(['c365', 'c366', ...], {'c365': ['Switch', 0.0, 1.0], 'c366': ['Switch', 0.0, 1.0], ...})
+        """
+        point_sql = "SELECT serial_number,alarm_low_limit,alarm_up_limit,signal_type FROM data_point_tbl WHERE buzzer_alarm=1"
+        point_info = self._storage.execute_sql(point_sql)
+        point_list = []
+        point_dict = {}
+        for index in point_info:
+            point_list.append('c' + str(index['serial_number']))
+            point_dict['c' + str(index['serial_number'])] = [index['signal_type'], index['alarm_low_limit'], index['alarm_up_limit']]
+
+        return point_list, point_dict
+
+
+    def get_real_data(self, point_list):
+
+        last_data_dict = self._storage.memoryStorage.get_value(point_list)
+        # last_data_dict = {'c1': None, 'c2': 25.5, 'c3': 70, 'c4': 20, 'c5': 100, 'c6': 10, 'c365': 1, 'c366': 0, 'c367': 0, 'c368': 0, 'c369': 1, 'c370': 0, 'c371': 0, 'c372': 0, 'c373': 0, 'c374': 0, 'c375': 0, 'c376': 0, 'c377': 0, 'c416': 0, 'c417': 0}
+
+        # 添加水下设备清洗配置信息
+        get_underwater_equip_sql = f"SELECT device_name, next_clean_time FROM underwater_equipment_clean WHERE function_status=1;"
+        get_underwater_equip_info = self._storage.execute_sql(get_underwater_equip_sql)
+        for index in get_underwater_equip_info:
+            last_data_dict[index["device_name"]] = index["next_clean_time"]
+
+        return last_data_dict

+ 9 - 0
005_H570/jikong_script/api_context.py

@@ -0,0 +1,9 @@
+from apis.api_init import *
+
+
+class ApiContext:
+    def set_api_object(self, object):
+        self.api_object = eval(object)()
+
+    def operation(self, request):
+        return self.api_object.operation(request)

+ 27 - 0
005_H570/jikong_script/apis/add_user_operation.py

@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/16 13:53
+@LastEditTime:  
+@Description: 记录操作时间,操作用户,操作内容,操作的设备
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+import time
+
+class AddUserOperation(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        now_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
+        user = request['user']
+        device_name = request['device_name']
+        detail = request['detail']
+
+        insert_sql = "INSERT INTO user_operation_record (times, user, device_name, detail)VALUES (\'%s\', \'%s\', \'%s\', \'%s\');" % (now_time, user, device_name, detail)
+        res = operate_mysql.execute_sql(insert_sql)
+        if res is not None:
+            return "insert success"
+        else:
+            return "insert failed"

+ 33 - 0
005_H570/jikong_script/apis/alarm_change_limit.py

@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/21 14:42
+@Author: lxc
+@LastEditTime:
+@Desctiption: 报警页面的配置子页面:修改上限和下限
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+
+class AlarmChangeLimit(AbstractApi):
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        # serial_number = request['serial_number'].replace('c', '')
+        serial_number = request['serial_number']
+        alarm_low_limit = request['alarm_low_limit']
+        alarm_up_limit = request['alarm_up_limit']
+
+        sql_change = "UPDATE data_point_tbl SET alarm_low_limit=%s, alarm_up_limit=%s WHERE serial_number=%s" % (alarm_low_limit, alarm_up_limit, serial_number)
+        try:
+            result = operate_mysql.execute_update_sql(sql_change)
+        except Exception as e:
+            self._log.error(e)
+            result = False
+
+        return result

+ 56 - 0
005_H570/jikong_script/apis/alarm_close_buzzer.py

@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/20 15:59
+@Author: lxc
+@LastEditTime:
+@Desctiption: 蜂鸣器报警消音、开关蜂鸣器、开关报警弹框、设置报警弹框间隔时间
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+
+class AlarmCloseBuzzer(AbstractApi):
+    """蜂鸣器消音、开关蜂鸣器"""
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        if "buzzer_operate" in request.keys():
+            operate = request["buzzer_operate"]        # closeBuzzer:关闭蜂鸣器,openBuzzer,开启蜂鸣器
+
+            if operate == "closeBuzzer":
+                update_sql = "UPDATE alarm_set SET buzzer_status=0;"
+
+            elif operate == "openBuzzer":
+                update_sql = "UPDATE alarm_set SET buzzer_status=1;"
+
+        elif "alarm_pop" in request.keys():
+            # 是否开启报警弹框提示,0=关闭,1=开启
+            alarm_pop = request['alarm_pop']
+            update_sql = f"UPDATE alarm_set SET alarm_pop={alarm_pop}"
+
+        elif "alarm_pop_period" in request.keys():
+            # 设置报警弹框间隔时间,单位:s
+            alarm_pop_period = request['alarm_pop_period']
+            update_sql = f"UPDATE alarm_set SET alarm_pop_period={alarm_pop_period}"
+
+        elif "alarm_cancel" in request.keys():
+            # 设置报警消息的状态为已读
+            id = request['alarm_cancel']['id']
+            if len(id) == 1:
+                update_sql = f"UPDATE alarm_tbl SET is_cancel=1 WHERE id={id[0]}"
+            else:
+                update_sql = f"UPDATE alarm_tbl SET is_cancel=1 WHERE id in {format(tuple(id))}"
+
+
+        if update_sql:
+            result = operate_mysql.execute_sql(update_sql)
+        else:
+            result = False
+
+        return result

+ 82 - 0
005_H570/jikong_script/apis/alarm_get_data.py

@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/21 14:42
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 报警页面:获取历史报警信息
+"""
+import time
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class AlarmGetData(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        device_name = request["device_name"]
+
+        # 查看点表中所有需要查看的点
+        if device_name == "all_device":
+            get_data_point_tbl = "SELECT serial_number,device_name,io_point_name,alarm_low_limit,alarm_up_limit FROM data_point_tbl;"
+        else:
+            get_data_point_tbl = f"SELECT serial_number,device_name,io_point_name,alarm_low_limit,alarm_up_limit FROM data_point_tbl WHERE device_name=\'{device_name}\';"
+
+        data_point_info = operate_mysql.execute_sql(get_data_point_tbl)
+        # all_point_info = {'c365': {'device_name': 'moxa_e1210', 'io_point_name': '主配电板绝缘低', 'alarm_low_limit': 0.0, 'alarm_up_limit': 1.0}, ...}
+        all_point_info = {}
+        device_name_list = []
+        for each in data_point_info:
+            device_name_list.append(each["device_name"])
+            serial_number = "c"+str(each["serial_number"])
+            del each["serial_number"]
+            all_point_info[serial_number] = each
+
+
+        # 查看报警记录表中对应的报警信息
+        if request["alarm_point_status"] == 0:
+            # 查看实时报警信息
+            get_alarm_sql = "SELECT id, CAST(create_time AS CHAR) AS create_time,point_name,data,is_cancel,signal_type FROM alarm_tbl WHERE alarm_point_status=0 ORDER BY `create_time` DESC;"
+        elif request["alarm_point_status"] == 1:
+            # 查询历史报警信息
+            time_begin = request["time_begin"]
+            time_end = request["time_end"]
+            get_alarm_sql = f"SELECT id, CAST(create_time AS CHAR) AS create_time,point_name,data,is_cancel,signal_type " \
+                            f"FROM alarm_tbl WHERE alarm_point_status=1 and create_time BETWEEN '{time_begin}' AND '{time_end}' ORDER BY `create_time` DESC;"
+
+
+        get_alarm_info = operate_mysql.execute_sql(get_alarm_sql)
+        alarm_list = []
+        for alarm in get_alarm_info:
+            # alarm = {'create_time': '2022-06-17 14:21:10', 'point_name': 'c3', 'data': 70.0, 'is_cancel': 0, 'signal_type': 'Analog'}
+            point_name = alarm["point_name"]
+            if point_name in all_point_info.keys():
+                point_info = all_point_info[point_name]
+                del alarm["point_name"]
+                alarm_list.append(dict(alarm, **point_info))
+            else:
+                signal_type = alarm["signal_type"]
+                if signal_type == "device_clean":
+                    # 水下设备清洗的报警提示
+                    alarm["device_name"] = signal_type
+                    alarm["io_point_name"] = alarm["point_name"]
+                    del alarm["point_name"]
+                    alarm["alarm_low_limit"] = None
+                    alarm["alarm_up_limit"] = None
+
+                    device_name_list.append(signal_type)
+                    alarm_list.append(alarm)
+
+        get_alarm_status = "SELECT buzzer_status,alarm_pop,alarm_pop_period FROM `alarm_set`;"
+        get_alarm_status = operate_mysql.execute_sql(get_alarm_status)      # 获取蜂鸣器报警功能是否开启、报警弹框是否开启、报警弹框间隔时间(s)
+
+        res = {
+            "buzzer_status": get_alarm_status[0]['buzzer_status'],
+            "alarm_pop": get_alarm_status[0]['alarm_pop'],
+            "alarm_pop_period": get_alarm_status[0]['alarm_pop_period'],
+            "device_name": list(set(device_name_list)),
+            "alarm_info": alarm_list
+        }
+        return res
+

+ 32 - 0
005_H570/jikong_script/apis/alarm_get_point_config.py

@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/21 14:42
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 报警页面的配置子页面:获取该平台的所有点的信息
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class AlarmGetPointConfig(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        device_name = request["device_name"]
+
+        # 查看点表中所有需要查看的点
+        if device_name == "all_device":
+            get_point_sql = "SELECT serial_number,device_name_CN AS device_name,io_point_name,unit,alarm_low_limit,alarm_up_limit,signal_type,buzzer_alarm FROM data_point_tbl;"
+        else:
+            get_point_sql = f"SELECT serial_number,device_name_CN AS device_name,io_point_name,unit,alarm_low_limit,alarm_up_limit,signal_type,buzzer_alarm " \
+                            f"FROM data_point_tbl WHERE device_name=\'{device_name}\';"
+
+
+        all_point = operate_mysql.execute_sql(get_point_sql)
+
+
+        return all_point
+

+ 36 - 0
005_H570/jikong_script/apis/alarm_link_buzzer.py

@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/21 14:42
+@Author: lxc
+@LastEditTime:
+@Desctiption: 报警页面的配置子页面:修改与蜂鸣器的联动状态
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+
+class AlarmLinkBuzzer(AbstractApi):
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        # request = {"serial_number": [1, 2, 3, 4, 5], "buzzer_alarm": 1}
+
+        serial_number = request["serial_number"]
+        buzzer_alarm = request["buzzer_alarm"]
+        if len(serial_number) == 1:
+            update_sql = f"UPDATE data_point_tbl SET buzzer_alarm={buzzer_alarm} WHERE serial_number={serial_number[0]}"
+        else:
+            update_sql = f"UPDATE data_point_tbl SET buzzer_alarm={buzzer_alarm} WHERE serial_number in {format(tuple(serial_number))}"
+
+        try:
+            result = operate_mysql.execute_update_sql(update_sql)
+        except Exception as e:
+            self._log.error(e)
+            result = False
+
+        return result

+ 56 - 0
005_H570/jikong_script/apis/api_init.py

@@ -0,0 +1,56 @@
+from apis.get_unread_alarm import GetUnreadAlarm
+from apis.get_historical_data import GetHistoricalData
+from apis.cancel_alarm import CancelAlarm
+from apis.get_maintenance_info import GetMaintenanceInfo
+from apis.electric_mangement import ElectricMangement
+from apis.change_maintenance_info import ChangeMaintenanceInfo
+from apis.get_avg_data import GetAvgData
+from apis.get_min_data import GetMinData
+from apis.get_max_data import GetMaxData
+from apis.get_extreme_wind_speed import GetExtremeWindSpeed
+from apis.get_maximum_wind_speed import GetMaximumWindSpeed
+from apis.get_weather_history_data import GetWeatherHistoryData
+from apis.get_each_depth_data import GetEachDepthData
+from apis.change_alarm_limit import ChangeAlarmLimit
+from apis.reset_device_run_time import ResetDeviceRunTime
+from apis.read_point_info import ReadPointInfo
+from apis.flow_direction_radar_chart import FlowDirectionRadarChart
+from apis.change_touer_info import ChangeTouerInfo
+from apis.get_touer_info import GetTouerInfo
+from apis.add_user_operation import AddUserOperation
+from apis.get_user_operation import GetUserOperation
+from apis.get_feeding_advise import GetFeedingAdvise
+from apis.get_auto_feed_info import GetAutoFeedInfo
+from apis.change_auto_feed_info import ChangeAutoFeedInfo
+from apis.get_feeding_amount import GetFeedingAmount
+from apis.get_feeding_curve import GetFeedingCurve
+from apis.get_last_time_feeding_data import GetLastTimeFeedingData
+from apis.get_fishery_data_all import GetFisheryDataAll
+from apis.get_fishery_data_detail import GetFisheryDataDetail
+from apis.del_user_operation import DelUserOperation
+from apis.reset_total_feed_select_time import ResetTotalFeedSelectTime
+from apis.change_wind_light_config import ChangeWindLightConfig
+from apis.read_wind_light_config import ReadWindLightConfig
+from apis.get_auto_switch_device import GetAutoSwitchDevice
+from apis.change_auto_switch_device import ChangeAutoSwitchDevice
+from apis.cancel_moxa_e1210_alarm import CancelMoxaE1210Alarm
+from apis.gather_fish_light_change_mode import GatherFishLightChangeMode
+from apis.gather_fish_light_get_mode import GatherFishLightGetMode
+from apis.get_alarm_info import GetAlarmInfo
+from apis.get_underwater_equip_clean_info import GetUnderwaterEquipCleanInfo
+from apis.update_underwater_equip_clean_time import UpdateUnderwaterEquipCleanTime
+from apis.change_underwater_equip_clean_cycle import ChangeUnderwaterEquipCleanCycle
+from apis.get_moxa_e1210_alarm import GetMoxaE1210Alarm
+from apis.alarm_get_point_config import AlarmGetPointConfig
+from apis.alarm_change_limit import AlarmChangeLimit
+from apis.alarm_link_buzzer import AlarmLinkBuzzer
+from apis.alarm_get_data import AlarmGetData
+from apis.alarm_close_buzzer import AlarmCloseBuzzer
+from apis.yuntaideng_get_mode import YuntaidengGetMode
+from apis.yuntaideng_change_mode import YuntaidengChangeMode
+from apis.get_history_form_data import GetHistoryFormData
+from apis.get_history_curve_data import GetHistoryCurveData
+from apis.change_laliji_param import ChangeLalijiParam
+from apis.robot_real_data import RobotRealData
+from apis.robot_get_all_date import RobotGetAllDate
+from apis.robot_get_history_position_data import RobotGetHistoryPositionData

+ 30 - 0
005_H570/jikong_script/apis/cancel_alarm.py

@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/25 9:08
+@desc: 关闭实时报警
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+
+class CancelAlarm(AbstractApi):
+    """关闭报警"""
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        id = request['id']
+        if len(id) == 1:
+            sql = "UPDATE alarm_data_tbl SET is_cancel=1 WHERE id=%s;" % (id[0])
+        else:
+            sql = "UPDATE alarm_data_tbl SET is_cancel=1 WHERE id in %s;" % (format(tuple(id)))
+        try:
+            operate_mysql.execute_sql(sql)
+            return "告警关闭成功"
+        except Exception as e:
+            self._log.error(str(e))
+            return "告警关闭失败"

+ 31 - 0
005_H570/jikong_script/apis/cancel_moxa_e1210_alarm.py

@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/04/28 13:31
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 取消开关量综合报警的弹框提示报警信息
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class CancelMoxaE1210Alarm(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        io_point_name_dict = {}     # {'主配电板绝缘低': 'c365', '污水处理装置供电运行': 'c366', '污水处理装置综合报警': 'c367', ...}
+        select_io_point_name = "SELECT serial_number, io_point_name FROM `data_point_tbl` WHERE `station_name` = 'moxa_e1210' AND `io_point_name` IS NOT NULL;"
+        io_point_name_res = operate_mysql.execute_sql(select_io_point_name)
+        for each in io_point_name_res:
+            io_point_name_dict[each["io_point_name"]] = "c" + str(each["serial_number"])
+
+        for each_alarm in request:
+            times = each_alarm["alarm_time"]
+            serial_number = io_point_name_dict[each_alarm["io_point_name"]]
+            update_sql = f"UPDATE alarm_moxa_e1210 SET is_cancel=1 WHERE create_time=\'{times}\' AND serial_number=\'{serial_number}\';"
+            res = operate_mysql.execute_update_sql(update_sql)
+
+        return res
+

+ 28 - 0
005_H570/jikong_script/apis/change_alarm_limit.py

@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 17:55
+@desc: 水质监测系统:修改上限和下限
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+class ChangeAlarmLimit(AbstractApi):
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        serial_number = request['serial_number'].replace('c', '')
+        alarm_low_limit = request['alarm_low_limit']
+        alarm_up_limit = request['alarm_up_limit']
+
+        sql_change = "UPDATE data_point_tbl SET alarm_low_limit=%s, alarm_up_limit=%s WHERE serial_number=%s" % (alarm_low_limit, alarm_up_limit, serial_number)
+        try:
+            operate_mysql.execute_sql(sql_change)
+            return "change success"
+        except Exception as e:
+            self._log.error(str(e))
+            return "change failed"

+ 41 - 0
005_H570/jikong_script/apis/change_auto_feed_info.py

@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/19 10:33
+@LastEditTime:  
+@Description: 根据 id 修改自动投喂的配置
+"""
+import json
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+class ChangeAutoFeedInfo(AbstractApi):
+
+    def operation(self, request):
+        self._log = OutPutLog()
+        operate_mysql = EventStorage()
+        id = request['id']
+
+        change_sql = "UPDATE automatic_feeding_configuration SET"
+        for each in request:
+            data = request[each]
+            # 判断是否需要修改
+            if (data is not None) and (each != 'id'):
+                if each == 'phase_frequency':
+                    data = json.dumps(data)
+                if each == 'data_bait':
+                    data = eval(data)
+                change_sql = "%s %s=\'%s\'," % (change_sql, each, data)
+        change_sql = "%s WHERE id=%s;" % (change_sql.rstrip(','), id)
+
+        try:
+            res = operate_mysql.execute_sql(change_sql)
+            if res is not None:
+                return "change success"
+            else:
+                return "change failed"
+        except Exception as e:
+            self._log.error(str(e))
+            return "change failed"

+ 32 - 0
005_H570/jikong_script/apis/change_auto_switch_device.py

@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/01/06 15:16
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 修改 水下云台水下灯等设备定时开关 的相关信息
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+class ChangeAutoSwitchDevice(AbstractApi):
+
+    def operation(self, request):
+        self._log = OutPutLog()
+        operate_mysql = EventStorage()
+
+        device_name = request["device_name"]
+        status = request["status"]
+        change_sql = f"UPDATE auto_switch_device SET status={status}"
+
+        if status == 1:
+            open_time = request["open_time"]
+            close_time = request["close_time"]
+            change_sql = f"{change_sql},open_time='{open_time}',close_time='{close_time}'"
+
+        change_sql = f"{change_sql} WHERE device_name='{device_name}';"
+        res = operate_mysql.execute_sql(change_sql)
+
+        return res

+ 39 - 0
005_H570/jikong_script/apis/change_laliji_param.py

@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2023/01/18 08:38
+@Author: lxc
+@LastEditTime: 
+@Desctiption:修改拉力计的配置参数
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class ChangeLalijiParam(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        if isinstance(request, dict):
+            res = True
+            for k, v in request.items():
+                sql = f"UPDATE `laliji_config` SET `value` = '{v}' WHERE `serial_number`='{k}';"
+                datas = operate_mysql.execute_update_sql(sql)
+                if datas is False:
+                    res = False
+            
+            # 更新实时数据
+            get_param_sql = "SELECT `serial_number`,`value` FROM `laliji_config`;"
+            param_res = operate_mysql.execute_sql(get_param_sql)
+            param_dict = {}
+            for each in param_res:
+                param_dict[each['serial_number']] = each['value']
+            operate_mysql.real_time_data_storage(param_dict)
+
+        else:
+            res = "param is not dict!"
+
+
+        return res

+ 43 - 0
005_H570/jikong_script/apis/change_maintenance_info.py

@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/28 13:46
+@desc: 修改设备维保信息:待维保天数和上次维保时间
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from datetime import datetime, timedelta
+from dateutil.parser import parse
+from log import OutPutLog
+
+
+class ChangeMaintenanceInfo(AbstractApi):
+    """更新设备的维保信息:待维保天数和上次维保时间"""
+
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        device_name = request['deviceName']
+        last_maintenance_time = request['lastMaintenanceTime']
+        maintenance_cycle = request['maintenanceCycle']
+
+        now_time = datetime.now()
+        today_time = now_time.strftime('%Y-%m-%d')
+
+        # 下次维保时间
+        next_maintenance_time = (datetime.strptime(last_maintenance_time, "%Y-%m-%d").date() + timedelta(days=maintenance_cycle)).strftime("%Y-%m-%d")
+        waiting_days = (parse(next_maintenance_time) - parse(today_time)).days
+
+        update_days = "UPDATE maintenance_information SET maintenance_cycle=%s, last_maintenance_time=\'%s\', waiting_days=%s WHERE device_name=\'%s\';" % (maintenance_cycle, last_maintenance_time, waiting_days, device_name)
+        try:
+            operate_mysql.execute_sql(update_days)
+        except Exception as e:
+            self._log.error(e)
+
+        resturn_dict = {"device_name": device_name, "waiting_days": waiting_days}
+
+        return resturn_dict

+ 44 - 0
005_H570/jikong_script/apis/change_touer_info.py

@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/6/15 16:21
+@LastEditTime:
+@Description: 修改 有关料灌、饵料的基本参数
+"""
+import json
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+class ChangeTouerInfo(AbstractApi):
+
+    def operation(self, request):
+        self._log = OutPutLog()
+        operate_mysql = EventStorage()
+
+        id = request['id']
+
+        change_sql = "UPDATE touer_set SET"
+        for each in request:
+            data = request[each]
+            # 判断是否需要修改
+            if (data is not None) and (each != 'id'):
+                list_data = []
+                if type(data) is dict:
+                    for k in data:
+                        list_data.append(k)
+                        list_data.append(data[k])
+                    change_sql = "%s %s=json_object%s," % (change_sql, each, format(tuple(list_data)))
+                else:
+                    change_sql = "%s %s=\'%s\'," % (change_sql, each, data)
+        change_sql = "%s WHERE id=%s;" % (change_sql.rstrip(','), id)
+        try:
+            res = operate_mysql.execute_sql(change_sql)
+            if res is not None:
+                return "change success"
+            else:
+                return "change failed"
+        except Exception as e:
+            self._log.error(str(e))
+            return "change failed"

+ 29 - 0
005_H570/jikong_script/apis/change_underwater_equip_clean_cycle.py

@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/9/30 15:32
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 修改设备的清洗周期
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from datetime import timedelta
+
+class ChangeUnderwaterEquipCleanCycle(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        device_name = request["device_name"]
+        clean_cycle = request["clean_cycle"]
+
+        select_sql = "SELECT this_clean_time FROM underwater_equipment_clean WHERE device_name=\'%s\';" % (device_name)
+        this_clean_time = operate_mysql.execute_sql(select_sql)[0]["this_clean_time"]
+        next_clean_time = this_clean_time + timedelta(days=clean_cycle)
+
+        update_sql = "UPDATE underwater_equipment_clean SET clean_cycle=%s,next_clean_time=\'%s\' WHERE device_name=\'%s\';" % (clean_cycle, next_clean_time, device_name)
+        try:
+            operate_mysql.execute_sql(update_sql)
+        except Exception as e:
+            print(e)

+ 27 - 0
005_H570/jikong_script/apis/change_wind_light_config.py

@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+# @CreateTime: 2021/7/7 10:03
+# @Author: lxc
+# @LastEditTime: 
+# @Desctiption: 风光发电子系统界面:修改充电设备的参数
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class ChangeWindLightConfig(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        recharge_device_set = request['recharge_device_set']        # 充电设备配置 0:无;1:主发电机;2:应急发电机
+        recharge_device_start_voltage = request['recharge_device_start_voltage']    # 	充电设备启动电压(V)
+
+        sql_change = "UPDATE wind_light_configuration SET recharge_device_set=%s, recharge_device_start_voltage=%s;" % (recharge_device_set, recharge_device_start_voltage)
+        try:
+            operate_mysql.execute_sql(sql_change)
+            return "change success"
+        except Exception as e:
+            self._log.error(str(e))
+            return "change failed"

+ 33 - 0
005_H570/jikong_script/apis/del_user_operation.py

@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/19 16:53
+@LastEditTime:  
+@Description:  删除用户的操作记录,依据:id
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+class DelUserOperation(AbstractApi):
+
+    def operation(self, request):
+        self._log = OutPutLog()
+        operate_mysql = EventStorage()
+        id = request['id']
+
+        if len(id) == 1:
+            del_sql = "DELETE FROM user_operation_record WHERE id=%s;" % (id[0])
+        else:
+            del_sql = "DELETE FROM user_operation_record WHERE id in %s;" % (format(tuple(id)))
+
+        try:
+            res = operate_mysql.execute_sql(del_sql)
+            if res is not None:
+                return "delete success"
+            else:
+                return "delete failed"
+        except Exception as e:
+            self._log.error(e)
+            return "delete failed"

+ 218 - 0
005_H570/jikong_script/apis/electric_mangement.py

@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/26 10:19
+@desc: 电能管理界面
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+import datetime
+from datetime import timedelta
+import pandas
+from log import OutPutLog
+import calendar
+
+class ElectricMangement(AbstractApi):
+    """电能管理 界面的接口"""
+    def __init__(self):
+        self._log = OutPutLog()
+        self._operate_mysql = EventStorage()
+        self._now = datetime.datetime.now()                          # 2021-05-26 10:33:13.252703
+        self._today_date = self._now.strftime("%Y-%m-%d")   # 2021-05-26
+        self._yesterday_date = (self._now + timedelta(days=-1)).strftime("%Y-%m-%d")  # 2021-05-25
+        self._month_data = self._now.strftime("%Y-%m")      # 2021-05
+        self._last_month_data = datetime.date(self._now.year, self._now.month, 1) - datetime.timedelta(1)
+        self._year_data = self._now.strftime("%Y")
+
+    def operation(self, request):
+
+        # ===============================
+        # ========== 用电的计算 ==========
+        # ===============================
+
+        # 当日、当月用电趋势(kw-h)、 当日实时用电(kw-h)、当月累计用电(kw-h)
+        unit_electric = "kWh"
+        sql_each_device = "SELECT serial_number, device_name FROM data_point_tbl WHERE unit=\'%s\';" % (unit_electric)
+        res_each_device = self._operate_mysql.execute_sql(sql_each_device)
+        ele_day_all = {}            # 每天的用电总量
+        ele_minute_all = {}         # 每小时的用电总量
+
+        # 查询每台设备
+        for each1 in res_each_device:
+            ele_serial_number = "c" + str(each1["serial_number"])
+            ele_table_name = "table_" + each1["device_name"]
+            # 返回各设备每天的用电量(本月)
+            sql_ele_day = "SELECT DATE_FORMAT(times, '%%Y-%%m-%%d') AS t, MAX(%s) AS num FROM `%s` WHERE times>\'%s\' GROUP BY t;" % (ele_serial_number, ele_table_name, self._month_data)
+            # 返回各设备上个月最后一天的用电总量
+            # sql_ele_last_month = "SELECT DATE_FORMAT(times, '%%Y-%%m') AS t, MAX(%s) AS num FROM `%s` WHERE times<\'%s\' GROUP BY t ORDER BY t DESC LIMIT 1;" % (ele_serial_number, ele_table_name, self._month_data)
+            sql_ele_last_month = "SELECT times AS t, %s AS num FROM `%s` WHERE times<\'%s\' ORDER BY t DESC LIMIT 1;" % (ele_serial_number, ele_table_name, self._month_data)
+            res_ele_day = self.calculation_each_use(sql_ele_day,  sql_ele_last_month)
+            for each_ele in res_ele_day:
+                if each_ele in ele_day_all.keys():
+                    ele_day_all[each_ele] = ele_day_all[each_ele] + res_ele_day[each_ele]
+                else:
+                    ele_day_all[each_ele] = res_ele_day[each_ele]
+            # 返回各设备每小时的用电量(昨天和今天)
+            sql_ele_minute = "SELECT DATE_FORMAT(times, '%%Y-%%m-%%d %%H') AS t, MAX(%s) AS num FROM `%s` WHERE times>=\'%s\' GROUP BY t;" % (ele_serial_number, ele_table_name, self._yesterday_date)
+            # 返回各设备前天最后的用电量
+            sql_ele_before_yestyeday = "SELECT times, %s AS num FROM `%s` WHERE times<\'%s\' ORDER BY times DESC LIMIT 1;" % (ele_serial_number, ele_table_name, self._yesterday_date)
+            res_ele_minute = self.calculation_each_use(sql_ele_minute, sql_ele_before_yestyeday)
+            for each_ele in res_ele_minute:
+                if each_ele in ele_minute_all.keys():
+                    ele_minute_all[each_ele] = ele_minute_all[each_ele] + res_ele_minute[each_ele]
+                else:
+                    ele_minute_all[each_ele] = res_ele_minute[each_ele]
+
+
+        # 当月用电趋势
+        ele_time_day = []      # 当月每天的日期
+        ele_day_use = []       # 当月每天的用电量
+        for k in sorted(ele_day_all):
+            ele_time_day.append(k)
+            ele_day_use.append('%.1f' % ele_day_all[k])
+
+        # # 昨天和今天的趋势分组
+        ele_minute_trend = self.group_today_yesterday(ele_minute_all)
+        ele_time_minute = ele_minute_trend[0]       # 昨日和今日的时刻(按小时划分)
+        ele_today_ues = ele_minute_trend[1]             # 今天每小时的用电量
+        ele_yesterday_ues = ele_minute_trend[2]         # 昨天每小时的用电量
+
+
+        # ===============================
+        # ========== 流量的计算 ==========
+        # ===============================
+        flow_serial_number = "c610"
+        flow_table_name = "table_liuliangji"
+
+        # # ① 今年流量趋势(t)
+        flow_time_day = []      # 今年的日期
+        flow_day_use = []       # 今年日期对应的流量
+        # 返回今年的累计流量
+        sql_flow_day = "SELECT DATE_FORMAT(times, '%%Y-%%m-%%d') AS t, MAX(%s) AS num FROM `%s` WHERE times>\'%s\' GROUP BY t;" % (flow_serial_number, flow_table_name, self._year_data)
+        # 返回去年最后的流量记录
+        # sql_flow_last_month = "SELECT DATE_FORMAT(times, '%%Y-%%m') AS t, MAX(%s) AS num FROM `%s` WHERE times<\'%s\' GROUP BY t ORDER BY t DESC LIMIT 1;;" % (flow_serial_number, flow_table_name, self._month_data)
+        sql_flow_last_month = "SELECT times, %s AS num FROM `%s` WHERE times<\'%s\' ORDER BY times DESC LIMIT 1;" % (flow_serial_number, flow_table_name, self._year_data)
+        res_flow_day_use = self.calculation_each_use(sql_flow_day, sql_flow_last_month)      # {'2021-05-24': 10.0, '2021-05-25': 1.0, '2021-05-26': 4.0, '2021-05-27': 5.0, '2021-05-28': 4.0, ...}
+        for k in sorted(res_flow_day_use):
+            flow_time_day.append(k)
+            if str(res_flow_day_use[k]) == "0.0":
+                flow_day_use.append(None)
+            else:
+                flow_day_use.append('%.2f' % res_flow_day_use[k])
+
+
+        # ②当年流量趋势(t)(按月划分)
+        flow_month_time = []
+        flow_month_num = []
+        sql_flow_month = "SELECT DATE_FORMAT(times, '%%Y-%%m') AS t, MAX(%s) AS num FROM `%s` WHERE times>=\'%s\' GROUP BY t;" % (flow_serial_number, flow_table_name, self._year_data)
+        sql_flow_last_year = "SELECT times, %s AS num FROM `%s` WHERE times<\'%s\' ORDER BY times DESC LIMIT 1;" % (flow_serial_number, flow_table_name, self._year_data)
+        res_flow_month = self.calculation_each_use(sql_flow_month, sql_flow_last_year)
+        for i in range(1, 13):
+            if len(str(i)) == 2:
+                month_time = self._year_data + "-" + str(i)
+            else:
+                month_time = self._year_data + "-0" + str(i)
+            if month_time not in res_flow_month.keys():
+                if month_time <= self._month_data:
+                    res_flow_month[month_time] = 0
+                if month_time > self._month_data:
+                    res_flow_month[month_time] = 0
+        for k in sorted(res_flow_month.keys()):
+            flow_month_time.append(k)
+            ll_num = str("%.2f" % res_flow_month[k])
+            if ll_num == "0.00":
+                flow_month_num.append(None)
+            else:
+                flow_month_num.append(ll_num)
+
+
+        for i in range(calendar.monthrange(int(self._month_data[:4]), int(self._month_data[-2:]))[1] + 1)[1:]:
+            if len(str(i)) == 2:
+                each_day = self._month_data + '-' + str(i)
+            else:
+                each_day = self._month_data + '-0' + str(i)
+            if each_day not in ele_time_day:
+                ele_time_day.append(each_day)
+                ele_day_use.append('null')
+
+
+
+
+        return_dict = {
+            "ele_time_day": ele_time_day, "ele_day_use": ele_day_use,
+            "ele_time_minute": ele_time_minute, "ele_today_ues": ele_today_ues, "ele_yesterday_ues": ele_yesterday_ues,
+            "flow_time_day": flow_time_day, "flow_day_use": flow_day_use,
+            "flow_month_time": flow_month_time, "flow_month_num": flow_month_num
+        }
+
+        return return_dict
+
+
+
+
+    def calculation_each_use(self, sql, sql_before_yesterday):
+        """
+        计算各设备每小时 / 每天的用电量
+        :param sql:
+        :return:
+        """
+        dicts = {}
+        group_time = []         # 分组后的时间
+        group_use = []          # 分组时间内的用量
+        for each in self._operate_mysql.execute_sql(sql):
+            group_time.append(each['t'])
+            group_use.append(each['num'])
+
+
+        if len(group_time) > 0:
+            dicts[group_time[0]] = group_use[0]
+            if len(group_time) >= 2:
+                for i in range(len(group_time) - 1):
+                    each_time = group_time[i + 1]
+                    each_use = group_use[i + 1] - group_use[i]  # 每小时的实际用电
+                    if each_use < 0:
+                        each_use = 0
+                    dicts[each_time] = each_use
+            before_use = self._operate_mysql.execute_sql(sql_before_yesterday)
+            if len(dicts) > 0 and len(before_use) > 0:
+                before_time = min(dicts.keys())
+                dicts[before_time] = dicts[before_time] - before_use[0]['num']
+
+        return dicts
+
+
+
+    def group_today_yesterday(self, datas):
+        """
+        将昨天和今天的用电量/累计流量分组
+        :param datas:字典,关键字是时间(昨天和今天的时间,按照小时划分),值是每小时的实际用量(电量或流量)
+        :return:
+        """
+        # 昨天和今天的趋势分组
+        today_time = []         # 当日的时刻(按小时划分)
+        today_use = []          # 当日每个时刻的用量
+        yesterday_time = []     # 昨日的时刻(按小时划分)
+        yesterday_use = []      # 昨日每个时刻的用量
+        for k in sorted(datas):
+            day_part = k[:10]           # 2021-05-26
+            hour_part = k[-2:] + ":00"  # 19:00
+            use_value = '%.1f' % datas[k]
+            if day_part == self._yesterday_date:
+                yesterday_time.append(hour_part)
+                yesterday_use.append(use_value)
+            elif day_part == self._today_date:
+                today_time.append(hour_part)
+                today_use.append(use_value)
+
+        # 通过数据帧整合昨日和今日的用量
+        df_today_use = pandas.DataFrame({self._today_date: today_use}, index=today_time)
+        df_yesterday_use = pandas.DataFrame({self._yesterday_date: yesterday_use}, index=yesterday_time)
+
+        df = (pandas.concat([df_yesterday_use, df_today_use], axis=1)).sort_index()       # 合并,并按index排序
+        df = df.where(df.notnull(), 'null')                        # 将nan替换为'null'
+        time_minute = df.index.tolist()
+        today_ues = df[self._today_date].tolist()
+        yesterday_ues = df[self._yesterday_date].tolist()
+
+        return time_minute, today_ues, yesterday_ues

+ 39 - 0
005_H570/jikong_script/apis/flow_direction_radar_chart.py

@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/4 13:53
+@LastEditTime:  
+@Description:   
+"""
+
+from abstract_api import AbstractApi
+import json
+import requests
+from log import OutPutLog
+from apis.operate_mysql import OperateMysql
+import traceback
+
+
+class FlowDirectionRadarChart(AbstractApi):
+
+    def operation(self, request):
+        self._log = OutPutLog()
+        data_dict = {}
+        operate_mysql = OperateMysql()
+        table_name = "table_" + request['deviceName']
+        limit = request['limit']
+        speed = request['speed']
+        direction = request['direction']
+        sql = "SELECT * FROM %s order by times desc limit %s" % (table_name, limit)
+        res = operate_mysql.execute_sql(sql)
+
+        if len(res) != 0:
+            for index in res:
+                for s in speed:
+                    data_dict.setdefault('direction_list', []).append(index[s])
+                for d in direction:
+                    data_dict.setdefault('speed_list', []).append(index[d])
+
+            return data_dict
+        else:
+            return None

+ 47 - 0
005_H570/jikong_script/apis/gather_fish_light_change_mode.py

@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/11/29 17:18
+@Author: lxc
+@LastEditTime: 
+@Desctiption:水下聚鱼灯远程控制功能:修改控制模式
+"""
+
+import json
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+
+class GatherFishLightChangeMode(AbstractApi):
+    """修改聚鱼灯的控制模式及相关信息"""
+
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        location = request["location"]
+        control_mode = request["control_mode"]
+
+        sql = f"UPDATE gather_fish_light_control SET control_mode={control_mode}"
+
+        if control_mode == 0:
+            # 光敏控制模式
+            pass
+        elif control_mode == 1:
+            # 手动控制模式
+            light_status = request["status"]
+            sql = f"{sql}, status={light_status}"
+        elif control_mode == 2:
+            # 定时控制模式
+            definite_time = json.dumps(request["definite_time"])
+            sql = f"{sql}, definite_time=\'{definite_time}\'"
+
+        sql = f"{sql} WHERE location=\'{location}\';"
+        res = operate_mysql.execute_update_sql(sql)
+        if res is False:
+            self._log.error(f"聚鱼灯控制模式修改失败!{sql}")
+
+
+        return res

+ 51 - 0
005_H570/jikong_script/apis/gather_fish_light_get_mode.py

@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/11/30 9:15
+@Author: lxc
+@LastEditTime: 
+@Desctiption:水下聚鱼灯远程控制功能:获取控制模式
+"""
+
+import json
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+
+class GatherFishLightGetMode(AbstractApi):
+    """获取聚鱼灯的控制模式及相关信息"""
+
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        sql = "SELECT location,control_mode,status,definite_time FROM gather_fish_light_control;"
+        datas = operate_mysql.execute_sql(sql)
+
+        if datas is not None and len(datas) > 1:
+            return datas
+        else:
+            return False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 70 - 0
005_H570/jikong_script/apis/get_alarm_info.py

@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/05/06 10:35
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 返回平台所有类型的报警信息
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+import datetime
+
+
+class GetAlarmInfo(AbstractApi):
+
+    def operation(self, request):
+        self.operate_mysql = EventStorage()
+        all_alarm_dict = {}
+
+        # 水下设备清洗的提示
+        underwater_equip_alarm = self.get_underwater_equip_alarm()
+        all_alarm_dict["水下设备清洗提示报警"] = underwater_equip_alarm
+
+        # 开关量综合报警
+        moxa_e1210_alarm = self.get_moxa_e1210_alarm()
+        all_alarm_dict["开关量综合报警提示"] = moxa_e1210_alarm
+
+
+        return all_alarm_dict
+
+
+
+    def get_underwater_equip_alarm(self):
+        """水下设备清洗的提示"""
+        underwater_equip_alarm_sql = "SELECT device_name, this_clean_time, clean_cycle, next_clean_time FROM underwater_equipment_clean WHERE function_status=1;"
+        underwater_equip_alarm_sql_res = self.operate_mysql.execute_sql(underwater_equip_alarm_sql)
+        result = []
+        if len(underwater_equip_alarm_sql_res) > 0:
+            now_time = datetime.datetime.now()
+            for each in underwater_equip_alarm_sql_res:
+                if now_time >= each["next_clean_time"]:
+                    result.append(each)
+
+        return result
+
+
+
+    def get_moxa_e1210_alarm(self):
+        """开关量综合报警"""
+        io_point_name_dict = {}     # {'c365': '主配电板绝缘低', 'c366': '污水处理装置供电运行', 'c367': '污水处理装置综合报警', ...}
+        select_io_point_name = "SELECT serial_number, io_point_name FROM `data_point_tbl` WHERE `station_name` = 'moxa_e1210' AND `io_point_name` IS NOT NULL;"
+        io_point_name_res = self.operate_mysql.execute_sql(select_io_point_name)
+        for each in io_point_name_res:
+            io_point_name_dict["c" + str(each["serial_number"])] = each["io_point_name"]
+
+        return_alarm_list = []
+        select_sql = "SELECT CAST(create_time AS CHAR) AS create_time, CAST(update_time AS CHAR) AS update_time, serial_number FROM alarm_moxa_e1210 WHERE is_cancel=0;"
+        alarm_datas = self.operate_mysql.execute_sql(select_sql)
+        if alarm_datas:
+            for each in alarm_datas:
+                each_alarm = {
+                    "alarm_create_time": each["create_time"],
+                    "alarm_update_time": each["update_time"],
+                    "io_point_name": io_point_name_dict[each["serial_number"]]
+                }
+                return_alarm_list.append(each_alarm)
+
+        return return_alarm_list
+

+ 46 - 0
005_H570/jikong_script/apis/get_auto_feed_info.py

@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/19 9:47
+@LastEditTime:
+@Description: 获取自动投喂的配置信息,默认有10条数据,全部查询
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetAutoFeedInfo(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        sql = "SELECT id, mode, feeding_port, feeding_line, CAST(time_begin AS CHAR) as time_begin, date_bait, CAST(time_end AS CHAR) as time_end, feeding_amount, bait_fall_regulation, phase_frequency, activation FROM automatic_feeding_configuration;"
+        datas = operate_mysql.execute_sql(sql)
+        weekStr = "周日周一周二周三周四周五周六"
+        # port_info_list = ["1号口","2号口"]
+
+        if datas is not None:
+            if len(datas) != 0:
+                list_data = []
+                for each in datas:
+                    dict_each = {}
+                    for k in each:
+                        # select 会将查到的json格式的值转为str,这里将其转为dict格式,以便返回json格式的字符串
+                        if k == 'phase_frequency' and each[k] is not None:
+                            dict_each[k] = eval(each[k])
+                        elif k == 'date_bait':
+                            list_week = []
+                            for date in eval(each[k]):
+                                list_week.append(weekStr[date*2: date*2+2])
+                            dict_each[k] = list_week
+                        # elif k == 'feeding_port':
+                        #     dict_each[k] = port_info_list[each[k]]
+                        else:
+                            dict_each[k] = each[k]
+                    list_data.append(dict_each)
+                return list_data
+            else:
+                return None
+        else:
+            return "查询出错,请看日志"

+ 22 - 0
005_H570/jikong_script/apis/get_auto_switch_device.py

@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/01/06 14:59
+@Author: lxc
+@LastEditTime:
+@Desctiption: 获取 水下云台水下灯等设备定时开关 的相关信息
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetAutoSwitchDevice(AbstractApi):
+    """获取 水下云台水下灯等设备定时开关 的相关信息"""
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        sql = "SELECT device_name,CAST(open_time AS CHAR) as open_time,CAST(close_time AS CHAR) as close_time,status,light_status FROM auto_switch_device;"
+        datas = operate_mysql.execute_sql(sql)
+
+        return datas

+ 30 - 0
005_H570/jikong_script/apis/get_avg_data.py

@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 11:37
+@desc: 
+"""
+
+
+import json
+from abstract_api import AbstractApi
+from apis.operate_mysql import OperateMysql
+import requests
+from log import OutPutLog
+import traceback
+
+class GetAvgData(AbstractApi):
+   
+    def operation(self, request):
+        operate_mysql = OperateMysql()
+        basic_data = request['basic_data']
+        serial_number = basic_data.replace('c', '')
+        res1 = operate_mysql.return_result(request, serial_number)
+        sql = "SELECT avg(%s) FROM %s WHERE times > \'%s\' and times < \'%s\';" % (basic_data, res1['table_name'], res1['begin_time'], res1['end_time'])
+        res2 = operate_mysql.execute_sql(sql)
+        avg_value = res2[0]['avg(' + basic_data + ')']
+        if avg_value is None:
+            return None
+        else:
+            res = {request['key']: ("%.2f" % avg_value)}
+            return res

+ 72 - 0
005_H570/jikong_script/apis/get_each_depth_data.py

@@ -0,0 +1,72 @@
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetEachDepthData(AbstractApi):
+    def operation(self, request):
+        """
+        c12:溶解度,solubility
+        c13:温度,temperature
+        c14:盐度,salt
+        c15:PH
+        c16:叶绿素,chlorophyll
+        c17:深度, depth
+        :param request: 
+        :return: 
+        """
+        operate_mysql = EventStorage()
+        begin_time = request['timeBegin']
+        end_time = request['timeEnd']
+
+        solubility = []
+        temperature = []
+        salt = []
+        ph = []
+        chlorophyll = []
+        depth = []
+        sql_datas = "SELECT avg(c12),avg(c13),avg(c14),avg(c15),avg(c16),avg(c17) FROM table_shuizhi WHERE times BETWEEN \'%s\' AND \'%s\' GROUP BY ROUND(c17,1) ORDER BY ROUND(c17,1);" % (begin_time, end_time)
+        res_datas = operate_mysql.execute_sql(sql_datas)
+        for each in res_datas:
+            try:
+                if each['avg(c12)'] is not None:
+                    solubility.append(round(each['avg(c12)'], 2))
+                else:
+                    solubility.append(None)
+
+                if each['avg(c13)'] is not None:
+                    temperature.append(round(each['avg(c13)'], 2))
+                else:
+                    temperature.append(None)
+
+                if each['avg(c14)'] is not None:
+                    salt.append(round(each['avg(c14)'], 2))
+                else:
+                    salt.append(None)
+
+                if each['avg(c15)'] is not None:
+                    ph.append(round(each['avg(c15)'], 2))
+                else:
+                    ph.append(None)
+
+                if each['avg(c16)'] is not None:
+                    chlorophyll.append(round(each['avg(c16)'], 2))
+                else:
+                    chlorophyll.append(None)
+
+                if each['avg(c17)'] is not None:
+                    depth.append(str(round(each['avg(c17)'], 2)) + 'm')
+                else:
+                    depth.append(None)
+            except Exception as e:
+                print("[GetEachDepthData] ERROR", e)
+
+        return_datas = {
+                "solubility": solubility,
+                "temperature": temperature,
+                "salt": salt,
+                "ph": ph,
+                "chlorophyll": chlorophyll,
+                "depth": depth
+            }
+
+        return return_datas
+

+ 41 - 0
005_H570/jikong_script/apis/get_extreme_wind_speed.py

@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 14:39
+@desc: 气象监测子系统:极大风速
+"""
+
+import json
+from abstract_api import AbstractApi
+from apis.operate_mysql import OperateMysql
+import requests
+from log import OutPutLog
+import traceback
+
+class GetExtremeWindSpeed(AbstractApi):
+
+    """返回极大风速(一定时间范围内的最大风速)"""
+    def operation(self, request):
+        operate_mysql = OperateMysql()
+        wind_direction = request['basic_datas'][0]      # 表示风向,如c1
+        wind_speed = request['basic_datas'][1]          # 表示风速,如c2
+
+        res_wind_speed = operate_mysql.return_result(request, wind_speed.replace('c', ''))
+        begin_time = res_wind_speed['begin_time']
+        end_time = res_wind_speed['end_time']
+
+        # 返回给定时间内的最大风速、最大风速对应的时间 [{'c2': 3.0, 'times': datetime.datetime(2021, 5, 4, 16, 25, 31)}]
+        sql1 = "SELECT %s, times FROM %s WHERE times >= \'%s\' and times < \'%s\' ORDER BY %s desc limit 1;" % (wind_speed, res_wind_speed['table_name'], begin_time, end_time, wind_speed)
+        res1 = operate_mysql.execute_sql(sql1)
+        if len(res1) != 0:
+            speed = res1[0][wind_speed]
+            times = res1[0]['times']
+            res_wind_direction = operate_mysql.return_result(request, wind_direction.replace('c', ''))
+            sql3 = "SELECT %s FROM %s WHERE times = \'%s\';" % (wind_direction, res_wind_direction['table_name'], times)
+            res3 = operate_mysql.execute_sql(sql3)[0][wind_direction]
+
+            dict_res = {request['keys'][0]: res3, request['keys'][1]: speed, request['keys'][2]: times.strftime('%Y-%m-%d %H:%M:%S')}
+
+            return dict_res
+        else:
+            return None

+ 51 - 0
005_H570/jikong_script/apis/get_feeding_advise.py

@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/6/19 15:26
+@desc: 智慧投饵接口
+"""
+
+
+from event_storage import EventStorage
+from abstract_api import AbstractApi
+
+class GetFeedingAdvise(AbstractApi):
+    def operation(self, request):
+        #投饵口朝向,1#:315°,2#:45°,3#:135°,4#:225°
+        #风向:c1,风速:c2,流速:c89,流向:c90
+        list = ["c1", "c2", "c89", "c90"]
+        gateway_storage = EventStorage()
+        dict = gateway_storage.get_real_data(list)
+        message = {}
+        wind_speed = self.str_to_flaot(dict['c2'])
+        wind_direction = self.str_to_flaot(dict['c1'])
+        flow_speed = self.str_to_flaot(dict['c89'])
+        flow_direction = self.str_to_flaot(dict['c90'])
+        #判断投喂条件 ,错误或警告状态时port为0,系统不选择投喂口
+        if wind_speed == None or wind_direction == None or flow_speed == None or flow_direction == None:
+            message['type'] = "ERROR"
+            message['port'] = 0
+            message['content'] = "环境监测数据获取异常,请监测传感器状态!"
+        else:
+            if wind_speed > 17.2 or flow_speed > 1.0:
+                message['type'] = "WARMING"
+                message['port'] = 0
+                message['content'] = "风速或流速过大,不建议进行投饵!"
+            else:
+                message['type'] = "NORMAL"
+                if flow_direction < 180 and flow_direction > 90:
+                    message['port'] = 1
+                if flow_direction <= 90:
+                    message['port'] = 2
+                if flow_direction >= 180 and flow_direction < 270:
+                    message['port'] = 3
+                if flow_direction >= 270:
+                    message['port'] = 4
+                message['content'] = "建议使用%s号投饵口进行投饵" % (message['port'])
+        return message
+
+    def str_to_flaot(self, str):
+        if str != None:
+            return float(str)
+        else:
+            return None

+ 35 - 0
005_H570/jikong_script/apis/get_feeding_amount.py

@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/19 9:47
+@LastEditTime:  
+@Description: 获取自动投喂的配置信息,默认有10条数据,全部查询
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetFeedingAmount(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        # 查询投饵总量的起始时间
+        time_sql = "SELECT CAST(select_time AS CHAR) as select_time FROM touer_set;"
+        time_begin = operate_mysql.execute_sql(time_sql)[0]
+
+        # sql = "SELECT SUM(feeding_amount),tank_number FROM fishery_data GROUP BY tank_number;"
+        sql = "SELECT SUM(feeding_amount),tank_number FROM fishery_data WHERE times > \'%s\' GROUP BY tank_number;" % (time_begin['select_time'])
+        datas = operate_mysql.execute_sql(sql)
+
+        dict_each = {"tank1": 0, "tank2": 0, "tank3": 0, "tank4": 0}
+        if datas is not None:
+            if len(datas) != 0:
+                for each in datas:
+                    dict_each["tank"+str(each['tank_number'])] = round(each['SUM(feeding_amount)'], 2)
+                return dict_each
+            else:
+                return dict_each
+        else:
+            return "查询出错,请看日志"

+ 63 - 0
005_H570/jikong_script/apis/get_feeding_curve.py

@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/19 9:47
+@LastEditTime:
+@Description: 获取自动投喂的配置信息,默认有10条数据,全部查询
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from datetime import datetime
+from log import OutPutLog
+
+class GetFeedingCurve(AbstractApi):
+
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        # 旋转输料器1号运行频率:c445
+        # 旋转输料器2号运行频率:c446
+        # 旋转输料器3号运行频率:c447
+        # 旋转输料器4号运行频率:c448
+        list = ["c445", "c446", "c447", "c448"]
+
+        real_data_dict = operate_mysql.get_real_data(list)
+        feeder_frequency = self.str_to_flaot(real_data_dict['c445']) + self.str_to_flaot(real_data_dict['c446']) + self.str_to_flaot(real_data_dict['c447']) + self.str_to_flaot(real_data_dict['c448'])
+        if feeder_frequency >= 0:
+            sql = "SELECT SUM(feeding_amount) FROM fishery_data WHERE feed_id = (select max(feed_id) from fishery_data);"
+            feeding_amount = operate_mysql.execute_sql(sql)
+
+            sql = "SELECT times,feeder_frequency FROM fishery_data WHERE feed_id = (select max(feed_id) from fishery_data);"
+            datas = operate_mysql.execute_sql(sql)
+            if datas is not None:
+                if len(datas) != 0:
+                    dict_each = {}
+                    times = []
+                    feeder_frequencys = []
+                    dict_each['feeding_amount'] = round(feeding_amount[0]['SUM(feeding_amount)'], 2)
+                    for each in datas:
+                        times.append(each['times'])
+                        feeder_frequencys.append(each['feeder_frequency'])
+                    dict_each['times'] = times
+                    dict_each['datas'] = feeder_frequencys
+                    self._log.debug(f"{datetime.now().strftime('%Y-%m-%y %H:%M:%S')}[GetFeedingCurve] success {dict_each['feeding_amount']}")
+                    return dict_each
+                else:
+                    self._log.debug(f"{datetime.now().strftime('%Y-%m-%y %H:%M:%S')}[GetFeedingCurve] failed len(datas) == 0")
+                    return None
+            else:
+                self._log.debug(f"{datetime.now().strftime('%Y-%m-%y %H:%M:%S')}[GetFeedingCurve] failed datas is None")
+                return "查询出错,请看日志"
+        else:
+            self._log.debug(f"{datetime.now().strftime('%Y-%m-%y %H:%M:%S')}[GetFeedingCurve] failed feeder_frequency<0")
+            return None
+
+    def str_to_flaot(self, str):
+        if str != None:
+            return float(str)
+        else:
+            return 0

+ 41 - 0
005_H570/jikong_script/apis/get_fishery_data_all.py

@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/6/21 14:48
+@LastEditTime:
+@Description: 获取 fishery_data 表的历史数据:返回每次投喂的总的情况,根据料灌编号、时间进行条件查询
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+
+class GetFisheryDataAll(AbstractApi):
+
+    def operation(self, request):
+
+        operate_mysql = EventStorage()
+        tank_num = request['tankNum']
+        time_begin = request['timeBegin']
+
+        if (tank_num is None) and (time_begin is None):
+            sql = "SELECT feed_id, MIN(times) AS time_begin, MAX(times) AS time_end, FORMAT(AVG(wind_speed),2) AS wind_speed, FORMAT(AVG(wind_direction),2) AS wind_direction, FORMAT(AVG(flow_speed),2) AS flow_speed, FORMAT(AVG(flow_direction),2) AS flow_direction, feeding_port, tank_number, FORMAT(AVG(feeder_frequency),2) AS feeder_frequency, FORMAT(AVG(fan_frequency),2) AS fan_frequency, FORMAT(SUM(feeding_amount),2) AS feeding_amount, feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life FROM fishery_data GROUP BY feed_id, feeding_port, tank_number,feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life;"
+        elif (tank_num is None) and (time_begin is not None):
+            time_end = request['timeEnd'] + " 23:59:59"
+            sql = "SELECT feed_id, MIN(times) AS time_begin, MAX(times) AS time_end, FORMAT(AVG(wind_speed),2) AS wind_speed, FORMAT(AVG(wind_direction),2) AS wind_direction, FORMAT(AVG(flow_speed),2) AS flow_speed, FORMAT(AVG(flow_direction),2) AS flow_direction, feeding_port, tank_number, FORMAT(AVG(feeder_frequency),2) AS feeder_frequency, FORMAT(AVG(fan_frequency),2) AS fan_frequency, FORMAT(SUM(feeding_amount),2) AS feeding_amount, feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life FROM fishery_data WHERE times BETWEEN \'%s\' and \'%s\' GROUP BY feed_id, feeding_port, tank_number,feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life;" % (time_begin, time_end)
+        elif (tank_num is not None) and (time_begin is None):
+            sql = "SELECT feed_id, MIN(times) AS time_begin, MAX(times) AS time_end, FORMAT(AVG(wind_speed),2) AS wind_speed, FORMAT(AVG(wind_direction),2) AS wind_direction, FORMAT(AVG(flow_speed),2) AS flow_speed, FORMAT(AVG(flow_direction),2) AS flow_direction, feeding_port, tank_number, FORMAT(AVG(feeder_frequency),2) AS feeder_frequency, FORMAT(AVG(fan_frequency),2) AS fan_frequency, FORMAT(SUM(feeding_amount),2) AS feeding_amount, feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life FROM fishery_data WHERE tank_number=%s GROUP BY feed_id, feeding_port, tank_number,feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life;" % (tank_num)
+        elif (tank_num is not None) and (time_begin is not None):
+            time_end = request['timeEnd'] + " 23:59:59"
+            sql = "SELECT feed_id, MIN(times) AS time_begin, MAX(times) AS time_end, FORMAT(AVG(wind_speed),2) AS wind_speed, FORMAT(AVG(wind_direction),2) AS wind_direction, FORMAT(AVG(flow_speed),2) AS flow_speed, FORMAT(AVG(flow_direction),2) AS flow_direction, feeding_port, tank_number, FORMAT(AVG(feeder_frequency),2) AS feeder_frequency, FORMAT(AVG(fan_frequency),2) AS fan_frequency, FORMAT(SUM(feeding_amount),2) AS feeding_amount, feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life FROM fishery_data WHERE tank_number=%s and times BETWEEN \'%s\' and \'%s\' GROUP BY feed_id, feeding_port, tank_number,feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life;" % (tank_num, time_begin, time_end)
+
+
+        datas = operate_mysql.execute_sql(sql)
+        if datas is not None:
+            feed_amount = 0
+            for each in datas:
+                feed_amount = feed_amount + float(each['feeding_amount'].replace(',', ''))
+            all_feed_amount = {"feed_amount": "%.2f" % float(feed_amount)}
+            return datas, all_feed_amount
+        else:
+            return "find error"

+ 25 - 0
005_H570/jikong_script/apis/get_fishery_data_detail.py

@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/6/21 17:13
+@LastEditTime: 
+@Description: 智慧投饵:查询每次投喂的详细信息,根据投喂id查询
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetFisheryDataDetail(AbstractApi):
+
+    def operation(self, request):
+
+        operate_mysql = EventStorage()
+        feed_id = request['feed_id']
+
+        sql = "SELECT times,wind_speed,wind_direction,flow_speed,flow_direction,feeder_frequency,fan_frequency,feeding_amount FROM fishery_data WHERE feed_id=%s;" % (feed_id)
+
+        datas = operate_mysql.execute_sql(sql)
+        if datas is not None:
+            return datas
+        else:
+            return "find error"

+ 79 - 0
005_H570/jikong_script/apis/get_historical_data.py

@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/25 11:14
+@desc: 查询电流、电压的历史数据
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+import datetime
+
+class GetHistoricalData(AbstractApi):
+    """查询历史数据(电流、电压等)"""
+    def operation(self, select_info):
+        operate_mysql = EventStorage()
+        now_time = datetime.datetime.now()           # 2021-05-26 10:33:13.252703
+        today_date = now_time.strftime("%Y-%m-%d")   # 2021-05-26
+        device_name = select_info['deviceName']
+        table_name = "table_" + select_info['deviceName']
+        select_time = select_info['selectTime']
+
+        io_point_dict = {}      # {'c151': 'Ua', 'c152': 'Ub', 'c153': 'Uc', 'c154': 'Ia', 'c155': 'Ib', 'c156': 'Ic', 'c157': 'P', 'c158': 'Q', 'c159': '正向有功电能值', 'c160': '正向无功电能值'}
+        sql1 = "SELECT serial_number, io_point_name FROM data_point_tbl WHERE device_name=\'%s\';" % (device_name)
+        for each in operate_mysql.execute_sql(sql1):
+            io_point_dict["c"+str(each['serial_number'])] = each['io_point_name']
+            if each['io_point_name'] == '正向有功电能值':
+                c_kWh = "c"+str(each['serial_number'])
+            if each['io_point_name'] == '正向无功电能值':
+                c_kVarh = "c" + str(each['serial_number'])
+
+        return_dict = {}
+        # 查给定日期的历史数据
+        sql2 = "SELECT * FROM `%s` WHERE DATE_FORMAT(times, '%%Y-%%m-%%d') = \'%s\';" % (table_name, select_time) # 指定日期的所有数据
+        all_data = operate_mysql.execute_sql(sql2)
+
+        if len(all_data) == 0:
+            # 查询日期无数据时,返回null
+            for k in io_point_dict:
+                return_dict.setdefault(io_point_dict[k], []).append(None)
+        else:
+            for history_data in all_data:
+                # history_data = {'id': 1, 'times': datetime.datetime(2021, 5, 25, 11, 1, 1), 'is_send': 0, 'c151': 45.0, 'c152': 78.0, 'c153': 24.0, 'c154': 78.0, 'c155': 54.0, 'c156': 74.0, 'c157': 71.0, 'c158': 32.0, 'c159': 54.0, 'c160': 31.0}
+                return_dict.setdefault("times", []).append(history_data['times'])
+                for k in history_data:
+                    # k = 'c151': 45.0
+                    if 'c' in k:
+                        io_point = io_point_dict[k]
+                        value1 = history_data[k]
+                        # 当日耗能实时参数 = 今天的最后一条数据 - 今天的第一条数据
+                        # 其他参数 = 今天的最后一条数据
+                        if k != c_kWh and k != c_kVarh:
+                            value = value1
+                        else:
+                            sql3 = "SELECT %s, %s FROM `%s` WHERE times>\'%s\' ORDER BY times LIMIT 1;" % (c_kWh, c_kVarh, table_name, select_time)  # 指定日期的第一条数据
+                            earliest_data = operate_mysql.execute_sql(sql3)  # {'c159': 1.2, 'c160': 2.4}
+                            value = value1 - earliest_data[0][k]
+                        return_dict.setdefault(io_point, []).append(value)
+
+        """
+        # 查最新的一条数据
+        sql4 = "SELECT * FROM `%s` ORDER BY times DESC LIMIT 1;" % (table_name)
+        latest_data = operate_mysql.execute_sql(sql4)
+        for k in latest_data[0]:
+            # k = 'c151': 45.0
+            if 'c' in k:
+                io_point = "latest_" + io_point_dict[k]
+                value1 = latest_data[0][k]
+                # 当日耗能实时参数 = 今天的最后一条数据 - 今天的第一条数据
+                # 其他参数 = 今天的最后一条数据
+                if k != c_kWh and k != c_kVarh:
+                    value = value1
+                else:
+                    sql5 = "SELECT %s FROM `%s` WHERE times>\'%s\' ORDER BY times LIMIT 1;" % (k, table_name, today_date)
+                    res_data = operate_mysql.execute_sql(sql5)
+                    value = value1 - res_data[0][k]
+                return_dict[io_point] = value
+        """
+
+        return return_dict

+ 78 - 0
005_H570/jikong_script/apis/get_history_curve_data.py

@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2023/01/09 15:09
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 获取多个参数的历史曲线数据
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetHistoryCurveData(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        serial_number = request['serial_number']
+        begin_time = request['timeBegin']
+        end_time = request['timeEnd']
+
+        # 查该序列号对应的表名
+        return_data = {
+            "t": []
+        }
+        for each in serial_number:
+            # {'t': [], 'c869': [], 'c870': [], 'c871': [], 'c872': [], 'c873': [], 'c874': []}
+            return_data[each] = []
+        sql_table_name = "SELECT device_name FROM data_point_tbl WHERE serial_number=%s" % (serial_number[0].replace('c', ''))
+        res_table_name = operate_mysql.execute_sql(sql_table_name)
+        if res_table_name:
+            table_name = "table_" + res_table_name[0]['device_name']
+
+            if table_name != 'table_laliji':
+                serial_number = str(serial_number)[1:-1].replace("'", "")
+                sql_data = "SELECT CAST(times AS CHAR) as t, %s FROM %s WHERE times BETWEEN \'%s\' and \'%s\' " \
+                           "ORDER BY times;" % (serial_number, table_name, begin_time, end_time)
+
+                res_data = operate_mysql.execute_sql(sql_data)
+                for each in res_data:
+                    for k, v in each.items():
+                        # print(k,v)
+                        return_data[k].append(v)
+
+            else:
+                # 拉力计的数据需要特殊计算
+                sql_data = "SELECT CAST(times AS CHAR) as t,c869,c870,c871,c872,c873,c874,c875,c876,c877,c878,c879," \
+                           "c880,c881,c882,c883,c884,c885,c886,c887,c888,c889,c890,c891,c892  FROM %s WHERE times " \
+                           "BETWEEN \'%s\' and \'%s\' ORDER BY times;" % (table_name, begin_time, end_time)
+                res_data = operate_mysql.execute_sql(sql_data)
+
+                serial_dict = {
+                    'c869': ['c875', 'c876', 'c877'],
+                    'c870': ['c878', 'c879', 'c880'],
+                    'c871': ['c881', 'c882', 'c883'],
+                    'c872': ['c884', 'c885', 'c886'],
+                    'c873': ['c887', 'c888', 'c889'],
+                    'c874': ['c890', 'c891', 'c892']
+                }
+                for each in res_data:
+                    # each = {'t': '2023-02-01 11:08:50', 'c869': 3.0, 'c870': 6.0, 'c871': 4.0, 'c872': 2.0}
+                    return_data['t'].append(each['t'])
+
+                    for k, v in serial_dict.items():
+                        original = each[k]  # S485读取的无符号整数
+                        a = each[v[0]]      # 参数A
+                        b = each[v[1]]      # 参数B
+                        f0 = each[v[2]]     # 参数f0
+                        if original and original == 0:
+                            return_data[k].append(0)
+                        elif original and original != 0 and a and b and f0:
+                            f = 80000000 / original         # 受力时频率f=80000000/(S485读取的无符号整数)
+                            p = a*(f*f-f0*f0) - b*(f-f0)        # P=A(f²-f0²)-B(f-f0)
+                            return_data[k].append(round(p, 2))
+                        else:
+                            return_data[k].append(None)
+
+        return return_data

+ 81 - 0
005_H570/jikong_script/apis/get_history_form_data.py

@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2023/01/09 15:09
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 获取多个参数的历史表单数据
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetHistoryFormData(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        serial_number = request['serial_number']
+        begin_time = request['timeBegin']
+        end_time = request['timeEnd']
+
+        # 查该序列号对应的表名
+        sql_table_name = "SELECT device_name FROM data_point_tbl WHERE serial_number=%s" % (serial_number[0].replace('c', ''))
+        res_table_name = operate_mysql.execute_sql(sql_table_name)
+        if res_table_name:
+            table_name = "table_" + res_table_name[0]['device_name']
+            if table_name != 'table_laliji':
+                serial_number = str(serial_number)[1:-1].replace("'", "")
+                sql_data = "SELECT CAST(times AS CHAR) as t, %s FROM %s WHERE times BETWEEN \'%s\' and \'%s\' " \
+                           "ORDER BY times;" % (serial_number, table_name, begin_time, end_time)
+            else:
+                sql_data = "SELECT CAST(times AS CHAR) as t,c869,c870,c871,c872,c873,c874,c875,c876,c877,c878,c879," \
+                           "c880,c881,c882,c883,c884,c885,c886,c887,c888,c889,c890,c891,c892  FROM %s WHERE times " \
+                           "BETWEEN \'%s\' and \'%s\' ORDER BY times;" % (table_name, begin_time, end_time)
+            res_data = operate_mysql.execute_sql(sql_data)
+
+
+            # 拉力计的数据需要特殊计算
+            if table_name == 'table_laliji':
+                #       f     A       B       f0
+                # lali1 c869  c875    c876    c877
+                # lali2 c870  c878    c879    c880
+                # lali3 c871  c881    c882    c883
+                # lali4 c872  c884    c885    c886
+                # lali5 c873  c887    c888    c889
+                # lali6 c874  c890    c891    c892
+                serial_dict = {
+                    'c869': ['c875', 'c876', 'c877'],
+                    'c870': ['c878', 'c879', 'c880'],
+                    'c871': ['c881', 'c882', 'c883'],
+                    'c872': ['c884', 'c885', 'c886'],
+                    'c873': ['c887', 'c888', 'c889'],
+                    'c874': ['c890', 'c891', 'c892']
+                }
+                new_res_data = []
+                for each in res_data:
+                    # each = {'t': '2023-02-01 11:08:50', 'c869': 3.0, 'c870': 6.0, 'c871': 4.0, 'c872': 2.0}
+                    data_dict = {}
+                    data_dict['t'] = each['t']
+
+                    for k, v in serial_dict.items():
+                        original = each[k]  # S485读取的无符号整数
+                        a = each[v[0]]      # 参数A
+                        b = each[v[1]]      # 参数B
+                        f0 = each[v[2]]     # 参数f0
+                        if original and original == 0:
+                            data_dict[k] = 0
+                        elif original and original != 0 and a and b and f0:
+                            f = 80000000 / original         # 受力时频率f=80000000/(S485读取的无符号整数)
+                            p = a*(f*f-f0*f0) - b*(f-f0)        # P=A(f²-f0²)-B(f-f0)
+                            data_dict[k] = round(p, 2)
+                        else:
+                            data_dict[k] = None
+                    new_res_data.append(data_dict)
+                res_data = new_res_data
+
+        else:
+            res_data = None
+
+        return res_data
+

+ 80 - 0
005_H570/jikong_script/apis/get_last_time_feeding_data.py

@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/19 9:47
+@LastEditTime:
+@Description: 获取自动投喂的配置信息,默认有10条数据,全部查询
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetLastTimeFeedingData(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        # 旋转输料器1号运行频率:c445
+        # 旋转输料器2号运行频率:c446
+        # 旋转输料器3号运行频率:c447
+        # 旋转输料器4号运行频率:c448
+        list = ["c445", "c446", "c447", "c448"]
+
+        real_data_dict = operate_mysql.get_real_data(list)
+        feeder_frequency = self.str_to_flaot(real_data_dict['c445']) + self.str_to_flaot(real_data_dict['c446']) + self.str_to_flaot(real_data_dict['c447']) + self.str_to_flaot(real_data_dict['c448'])
+        if feeder_frequency > 1:
+            sql = "SELECT SUM(feeding_amount) FROM fishery_data WHERE feed_id = (select max(feed_id) from fishery_data WHERE feed_id < (select max(feed_id) from fishery_data));"
+            feeding_amount = operate_mysql.execute_sql(sql)
+
+            sql = "SELECT times,tank_number,shelf_life FROM fishery_data WHERE feed_id = (select max(feed_id) from fishery_data WHERE feed_id < (select max(feed_id) from fishery_data)) ORDER BY times LIMIT 1;"
+            datas = operate_mysql.execute_sql(sql)
+        else:
+            sql = "SELECT SUM(feeding_amount) FROM fishery_data WHERE feed_id = (select max(feed_id) from fishery_data);"
+            feeding_amount = operate_mysql.execute_sql(sql)
+
+            sql = "SELECT times,tank_number,shelf_life FROM fishery_data WHERE feed_id = (select max(feed_id) from fishery_data) ORDER BY times LIMIT 1;"
+            datas = operate_mysql.execute_sql(sql)
+
+        parame = {1, 2, 3, 4}
+
+        if datas is not None:
+            if len(datas) != 0:
+                parame.remove(datas[0]['tank_number'])
+                dict_datas = {}
+                dict_each = {}
+                dict_each['feeding_amount'] = round(feeding_amount[0]['SUM(feeding_amount)'], 2)
+                dict_each['times'] = datas[0]['times']
+                dict_each['tank_number'] = datas[0]['tank_number']
+                dict_each['shelf_life'] = datas[0]['shelf_life']
+                dict_each['food_fall'] = 0
+                dict_datas["tank" + str(dict_each['tank_number'])] = dict_each
+
+                for tank_number in parame:
+                    sql = "SELECT SUM(feeding_amount) FROM fishery_data WHERE feed_id = (select max(feed_id) from fishery_data WHERE tank_number = %s );" % (tank_number)
+                    feeding_amount = operate_mysql.execute_sql(sql)
+
+                    sql = "SELECT times,tank_number,shelf_life FROM fishery_data WHERE feed_id = (select max(feed_id) from fishery_data WHERE tank_number = %s) ORDER BY times LIMIT 1;" % (tank_number)
+                    datas = operate_mysql.execute_sql(sql)
+                    if datas is not None:
+                        if len(datas) != 0:
+                            dict_each = {}
+                            dict_each['feeding_amount'] = round(feeding_amount[0]['SUM(feeding_amount)'], 2)
+                            dict_each['times'] = datas[0]['times']
+                            dict_each['tank_number'] = datas[0]['tank_number']
+                            dict_each['shelf_life'] = datas[0]['shelf_life']
+                            dict_each['food_fall'] = 0
+                            dict_datas["tank" + str(dict_each['tank_number'])] = dict_each
+
+                return dict_datas
+            else:
+                return None
+        else:
+            return "查询出错,请看日志"
+
+    def str_to_flaot(self, str):
+        if str != None:
+            return float(str)
+        else:
+            return 0
+

+ 32 - 0
005_H570/jikong_script/apis/get_maintenance_info.py

@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/25 11:21
+@desc: 返回所有设备的维保信息
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+
+class GetMaintenanceInfo(AbstractApi):
+    """返回设备的维保信息"""
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        # 返回维保信息
+        return_data = []
+        sql = "SELECT * FROM maintenance_information ORDER BY id;"
+        res = operate_mysql.execute_sql(sql)
+        for each_data in res:
+            res_dict = {"device_name": each_data['device_name'],
+                        "day_energy": each_data['day_energy'],
+                        "day_energy_percent": each_data['day_energy_percent'],
+                        "month_energy": each_data['month_energy'],
+                        "month_energy_percent": each_data['month_energy_percent'],
+                        "run_time": each_data['run_time'],
+                        "maintenance_cycle": each_data['maintenance_cycle'],
+                        "last_maintenance_time": (each_data['last_maintenance_time']).strftime('%Y-%m-%d %H:%M'),
+                        "waiting_days": each_data['waiting_days']}
+            return_data.append(res_dict)
+        return return_data

+ 29 - 0
005_H570/jikong_script/apis/get_max_data.py

@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 14:20
+@desc: 气象监测子系统:各点的最大值
+"""
+
+import json
+from abstract_api import AbstractApi
+from apis.operate_mysql import OperateMysql
+import requests
+from log import OutPutLog
+import traceback
+
+class GetMaxData(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = OperateMysql()
+        basic_data = request['basic_data']
+        serial_number = basic_data.replace('c', '')
+        res1 = operate_mysql.return_result(request, serial_number)
+
+        sql1 = "SELECT %s, CAST(times AS CHAR) as times FROM %s WHERE times > \'%s\' and times < \'%s\' ORDER BY %s desc limit 1;" % (basic_data, res1['table_name'], res1['begin_time'], res1['end_time'], basic_data)
+        res2 = operate_mysql.execute_sql(sql1)
+        if len(res2) != 0:
+            res = {request['keys'][0]: res2[0][basic_data], request['keys'][1]: res2[0]['times']}
+            return res
+        else:
+            return None

+ 55 - 0
005_H570/jikong_script/apis/get_maximum_wind_speed.py

@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 14:57
+@desc: 
+"""
+
+import json
+from abstract_api import AbstractApi
+from apis.operate_mysql import OperateMysql
+import datetime
+import requests
+from log import OutPutLog
+import traceback
+
+class GetMaximumWindSpeed(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = OperateMysql()
+        wind_direction = request['basic_datas'][0]      # 风向,如c1
+        wind_speed = request['basic_datas'][1]          # 风速,如c2
+
+        res_wind_speed = operate_mysql.return_result(request, wind_speed.replace('c', ''))
+        begin_time = res_wind_speed['begin_time']
+        end_time = res_wind_speed['end_time']
+
+        count = (int(request['end_time']) - int(request['begin_time'])) / 600
+        max_speed = 0
+        status = 0      # 状态,用于判断所查询的时间段内是否有数据
+        while count > 0:
+            time1 = begin_time+datetime.timedelta(minutes=10)
+
+            sql1 = "SELECT avg(%s) FROM %s WHERE times >= \'%s\' and times < \'%s\';" % (wind_speed, res_wind_speed['table_name'], begin_time, time1)
+            res1 = operate_mysql.execute_sql(sql1)
+            speed = res1[0]["avg(" + wind_speed + ")"]
+            if speed is not None:
+                status = 1  # 如果有数据,修改status,进行下一步查询
+                if speed > max_speed:
+                    max_speed = speed
+                    return_begin_time = begin_time
+                    return_end_time = time1
+
+            count = count - 1
+            begin_time = time1
+        if status == 1:
+            res_wind_direction = operate_mysql.return_result(request, wind_direction.replace('c', ''))
+            sql2 = "SELECT avg(%s) FROM %s WHERE times >= \'%s\' and times < \'%s\';" % (wind_direction, res_wind_direction['table_name'], return_begin_time, return_end_time)
+            res2 = operate_mysql.execute_sql(sql2)
+            max_wind_direction = res2[0]['avg(' + wind_direction + ')']
+
+            res = {request['keys'][0]: ("%.2f" % max_wind_direction), request['keys'][1]: ("%.2f" % max_speed), request['keys'][2]: return_begin_time.strftime('%Y-%m-%d %H:%M:%S')}
+
+            return res
+        else:
+            return None

+ 28 - 0
005_H570/jikong_script/apis/get_min_data.py

@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 14:06
+@desc: 
+"""
+
+import json
+from abstract_api import AbstractApi
+from apis.operate_mysql import OperateMysql
+import requests
+from log import OutPutLog
+import traceback
+
+class GetMinData(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = OperateMysql()
+        basic_data = request['basic_data']
+        serial_number = basic_data.replace('c', '')
+        res1 = operate_mysql.return_result(request, serial_number)
+        sql1 = "SELECT %s, CAST(times AS CHAR) as times FROM %s WHERE times > \'%s\' and times < \'%s\' AND `%s` IS NOT NULL ORDER BY %s limit 1;" % (basic_data, res1['table_name'], res1['begin_time'], res1['end_time'], basic_data, basic_data)
+        res2 = operate_mysql.execute_sql(sql1)
+        if len(res2) != 0:
+            res = {request['keys'][0]: res2[0][basic_data], request['keys'][1]: res2[0]['times']}
+            return res
+        else:
+            return None

+ 38 - 0
005_H570/jikong_script/apis/get_moxa_e1210_alarm.py

@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/04/28 11:26
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 获取开关量综合报警 弹框提示的报警信息
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetMoxaE1210Alarm(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        io_point_name_dict = {}     # {'c365': '主配电板绝缘低', 'c366': '污水处理装置供电运行', 'c367': '污水处理装置综合报警', ...}
+        select_io_point_name = "SELECT serial_number, io_point_name FROM `data_point_tbl` WHERE `station_name` = 'moxa_e1210' AND `io_point_name` IS NOT NULL;"
+        io_point_name_res = operate_mysql.execute_sql(select_io_point_name)
+        for each in io_point_name_res:
+            io_point_name_dict["c" + str(each["serial_number"])] = each["io_point_name"]
+
+
+        return_alarm_list = []
+        select_sql = "SELECT CAST(update_time AS CHAR) AS update_time, serial_number FROM alarm_moxa_e1210 WHERE is_cancel=0;"
+        alarm_datas = operate_mysql.execute_sql(select_sql)
+        if alarm_datas:
+            for each in alarm_datas:
+                each_alarm = {
+                    "alarm_time": each["update_time"],
+                    "io_point_name": io_point_name_dict[each["serial_number"]]
+                }
+
+                return_alarm_list.append(each_alarm)
+
+        return return_alarm_list
+

+ 33 - 0
005_H570/jikong_script/apis/get_touer_info.py

@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/6/15 15:21
+@LastEditTime:
+@Description: 获取有关料灌、饵料的基本参数
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetTouerInfo(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        sql_get_touer_info = "SELECT * FROM touer_set;"
+        get_touer_info = operate_mysql.execute_sql(sql_get_touer_info)
+
+        if len(get_touer_info) != 0:
+            list_data = []
+            for each in get_touer_info:
+                dict_each = {}
+                for k in each:
+                    # select 会将查到的json格式的值转为str,这里将其转为dict格式,以便返回json格式的字符串
+                    if "tank" in k and each[k] is not None:
+                        dict_each[k] = eval(each[k])
+                    else:
+                        dict_each[k] = each[k]
+                list_data.append(dict_each)
+            return list_data
+        else:
+            return None

+ 40 - 0
005_H570/jikong_script/apis/get_underwater_equip_clean_info.py

@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/9/24 10:19
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 返回水下设备清洗的相关信息
+"""
+
+
+from abstract_api import AbstractApi
+import datetime
+from event_storage import EventStorage
+
+
+class GetUnderwaterEquipCleanInfo(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        now_time = datetime.datetime.now()
+        info_sql = "SELECT * FROM underwater_equipment_clean;"
+        equip_info = operate_mysql.execute_sql(info_sql)
+        result = []
+        if len(equip_info) > 0:
+            for each in equip_info:
+                # 将清洗方法分行展示
+                clean_method = each["clean_method"]
+                clean_method = clean_method.replace("。", "。\n")
+                each["clean_method"] = clean_method
+
+                function_status = each["function_status"]
+                status = 0
+                if function_status == 1:
+                    if now_time >= each["next_clean_time"]:
+                        status = 1      # 设备是否需要清洗 0:不需要,1:需要
+                each["status"] = status
+                result.append(each)
+
+        return result

+ 31 - 0
005_H570/jikong_script/apis/get_unread_alarm.py

@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/25 9:24
+@desc: 获取未读报警
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetUnreadAlarm(AbstractApi):
+    """查询未读报警"""
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        # 查报警,
+        sql1 = "SELECT id,times,name,data FROM alarm_data_tbl WHERE is_cancel=0 ORDER BY times DESC;"
+        res1 = operate_mysql.execute_sql(sql1)
+
+        if len(res1) != 0:
+            list_alarm = []
+            for each in res1:
+                sql2 = "SELECT io_point_name FROM data_point_tbl WHERE serial_number=%s;" % (each['name'].replace('c', ''))
+                res2 = operate_mysql.execute_sql(sql2)
+                dict_alarm = {'id': each['id'], 'times': each['times'], 'data': each['data'], 'io_point_name': res2[0]['io_point_name']}
+                list_alarm.append(dict_alarm)
+
+            return list_alarm
+
+        else:
+            return None

+ 46 - 0
005_H570/jikong_script/apis/get_user_operation.py

@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime:    2021/6/16 14:13
+@LastEditTime:  
+@Description: 查询操作日志,可按时间段、操作用户、操作设备 进行条件查询
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class GetUserOperation(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        begin_time = request['timeBegin']
+        end_time = request['timeEnd'] + " 23:59:59"
+        user = request['user']
+        device_name = request['device_name']
+
+        # 按条件进行查询
+        if (begin_time is None) and (user is None) and (device_name is None):
+            select_sql = "SELECT * FROM user_operation_record;"
+        elif (begin_time is None) and (user is None) and (device_name is not None):
+            select_sql = "SELECT * FROM user_operation_record WHERE device_name=\'%s\';" % (device_name)
+        elif (begin_time is None) and (user is not None) and (device_name is None):
+            select_sql = "SELECT * FROM user_operation_record WHERE user=\'%s\';" % (user)
+        elif (begin_time is None) and (user is not None) and (device_name is not None):
+            select_sql = "SELECT * FROM user_operation_record WHERE user=\'%s\' AND device_name=\'%s\';" % (user, device_name)
+        elif (begin_time is not None) and (user is None) and (device_name is None):
+            select_sql = "SELECT * FROM user_operation_record WHERE times BETWEEN \'%s\' AND \'%s\';" % (begin_time, end_time)
+        elif (begin_time is not None) and (user is None) and (device_name is not None):
+            select_sql = "SELECT * FROM user_operation_record WHERE times BETWEEN \'%s\' AND \'%s\' AND device_name=\'%s\';" % (begin_time, end_time, device_name)
+        elif (begin_time is not None) and (user is not None) and (device_name is None):
+            select_sql = "SELECT * FROM user_operation_record WHERE times BETWEEN \'%s\' AND \'%s\' AND user=\'%s\';" % (begin_time, end_time, user)
+        elif (begin_time is not None) and (user is not None) and (device_name is not None):
+            select_sql = "SELECT * FROM user_operation_record WHERE times BETWEEN \'%s\' AND \'%s\' AND user=\'%s\' AND device_name=\'%s\';" % (begin_time, end_time, user, device_name)
+
+        res = operate_mysql.execute_sql(select_sql)
+        if res is not None:
+            return res
+        else:
+            return "find failed"
+
+

+ 47 - 0
005_H570/jikong_script/apis/get_weather_history_data.py

@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 15:52
+@desc: 获取历史数据,海水温度、海水深度、海水盐度、PH值、叶绿素等的历史数据
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from datetime import datetime
+
+class GetWeatherHistoryData(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        serial_number = request['serial_number']
+        begin_time = request['timeBegin']
+        end_time = request['timeEnd']
+
+        times = []
+        value = []
+        # 查该序列号对应的表名
+        sql_table_name = "SELECT device_name FROM data_point_tbl WHERE serial_number=%s" % (serial_number.replace('c', ''))
+        res_table_name = operate_mysql.execute_sql(sql_table_name)
+        table_name = "table_" + res_table_name[0]['device_name']
+        # 查数据(时间跨度超过7天,每分钟取一条数据)
+        time_length = (datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S')-datetime.strptime(begin_time, '%Y-%m-%d %H:%M:%S')).days
+        if -7 < time_length < 7:
+            sql_data = "SELECT CAST(times AS CHAR) as t, %s FROM %s WHERE times BETWEEN \'%s\' and \'%s\' ORDER BY times;" % (serial_number, table_name, begin_time, end_time)
+        else:
+            sql_data = f"SELECT (DATE_FORMAT(times, '%Y-%m-%d %H:%i')) AS t,  AVG({serial_number}) AS {serial_number} FROM {table_name} WHERE times BETWEEN \'{begin_time}\' and \'{end_time}\' GROUP BY t;"
+        res_data = operate_mysql.execute_sql(sql_data)
+
+        for each_data in res_data:
+            data = each_data[serial_number]
+            if data is None:
+                pass
+            else:
+                times.append(each_data['t'])
+                value.append(round(data, 3))
+
+        history_data = {
+            "times": times,
+            "value": value
+        }
+
+        return history_data

+ 73 - 0
005_H570/jikong_script/apis/operate_mysql.py

@@ -0,0 +1,73 @@
+import pymysql
+import traceback
+import time
+import datetime
+from configuration import Configuration
+
+
+class OperateMysql():
+    config = Configuration().get_system_config()
+    # config = config["hardDiskdataBase"]
+
+    # def __init__(self, config=config, port=3306, charset='utf8'):
+    def __init__(self, config=config, db="hardDiskdataBase", port=3306, charset='utf8'):
+        config = config[db]
+        self.host = config['ip']
+        self.user = config['username']
+        self.passwd = config['password']
+        self.db = config['dataBaseName']
+        self.port = port
+        self.charset = charset
+        self.conn = None
+        self._conn()
+
+    def _conn(self):
+        try:
+            self.conn = pymysql.connect(host=self.host, user=self.user, password=self.passwd, db=self.db, port=self.port, autocommit=True)
+            return True
+        except Exception as e:
+            print(e)
+            return False
+
+    def _reConn(self, num=28800, stime=3): #重试连接总次数为1天,这里根据实际情况自己设置,如果服务器宕机1天都没发现就......
+        _number = 0
+        _status = True
+        while _status and _number <= num:
+            try:
+                self.conn.ping()       #cping 校验连接是否异常
+                _status = False
+            except:
+                if self._conn()==True: #重新连接,成功退出
+                    _status = False
+                    break
+                _number +=1
+                time.sleep(stime)      #连接不成功,休眠3秒钟,继续循环,知道成功或重试次数结束
+
+
+    def execute_sql(self, sql):
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            print(traceback.format_exc())
+            return None
+
+    def return_result(self, point_statistic, serial_number):
+        # "parameter":{"key": "s2", "basic_data": "c2", "begin_time": "1618389390", "end_time": "1618389572"}
+        begin_time = datetime.datetime.fromtimestamp(int(point_statistic['begin_time']))
+        end_time = datetime.datetime.fromtimestamp(int(point_statistic['end_time']))
+        sql = "SELECT device_name FROM data_point_tbl WHERE serial_number=%s;" % (serial_number)
+        res = self.execute_sql(sql)
+        table_name = 'table_' + res[0]['device_name']
+        dict_res = {"table_name": table_name, "begin_time": begin_time, "end_time": end_time}
+
+        return dict_res
+
+
+# def database_parameters(self):
+#     config = {'ip': 'localhost', 'username': 'rootroot', 'password': 'rootroot', 'dataBaseName': 'shucai'}
+#     self.config = config

+ 30 - 0
005_H570/jikong_script/apis/read_point_info.py

@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/6/3 13:32
+@desc: 查点表的信息
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class ReadPointInfo(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        basic_datas = request['basic_datas']
+        if len(basic_datas) > 1:
+            point_list = []
+            for basic_data in basic_datas:
+                point_list.append(basic_data.replace('c', ''))
+            sql = "SELECT * FROM data_point_tbl where serial_number in %s;" % (format(tuple(point_list)))
+        elif len(basic_datas) == 1:
+            point = basic_datas[0].replace('c', '')
+            sql = "SELECT * FROM data_point_tbl where serial_number=%s;" % (point)
+        else:
+            sql = "SELECT * FROM data_point_tbl;"
+
+        res = operate_mysql.execute_sql(sql)
+
+        return res

+ 21 - 0
005_H570/jikong_script/apis/read_wind_light_config.py

@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+# @CreateTime: 2021/7/7 10:13
+# @Author: lxc
+# @LastEditTime: 
+# @Desctiption: 风光发电子系统界面:读充电设备的参数
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class ReadWindLightConfig(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        sql_read = "SELECT recharge_device_set, recharge_device_start_voltage FROM wind_light_configuration;"
+        res = operate_mysql.execute_sql(sql_read)
+
+        return res

+ 24 - 0
005_H570/jikong_script/apis/reset_device_run_time.py

@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/6/2 15:17
+@desc: 重置设备运行时间
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+
+class ResetDeviceRunTime(AbstractApi):
+
+    def operation(self, request):
+        """设备运行时间改为0"""
+        operate_mysql = EventStorage()
+        device_name = request['deviceName']
+
+        reset_sql = "UPDATE maintenance_information SET run_time=0 WHERE device_name=\'%s\';" % (device_name)
+        try:
+            operate_mysql.execute_sql(reset_sql)
+            return "reset success"
+        except:
+            return "reset failed"

+ 26 - 0
005_H570/jikong_script/apis/reset_total_feed_select_time.py

@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+# @CreateTime: 2021/7/5 16:25
+# @Author: lxc
+# @LastEditTime: 
+# @Desctiption: 智慧投饵子系统:将投饵总量的查询时间复位(改为当前时间)
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+import datetime
+
+class ResetTotalFeedSelectTime(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        now_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+        reset_sql = "UPDATE touer_set SET select_time=\'%s\';" % (now_time)
+        try:
+            operate_mysql.execute_sql(reset_sql)
+            return "reset success"
+        except:
+            return "reset failed"

+ 36 - 0
005_H570/jikong_script/apis/robot_get_all_date.py

@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2023/06/13 08:59
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 根据传入的月份,返回机器人指定月份的所有日期
+"""
+
+
+from abstract_api import AbstractApi
+from log import OutPutLog
+from apis.operate_mysql import OperateMysql
+
+
+class RobotGetAllDate(AbstractApi):
+
+    def operation(self, request):
+        """
+        根据传入的月份,返回机器人指定月份的所有日期
+        @param request: {"rovid" : "xunjian1", "month": "2023-06"}
+        @return:[{time: "2023-06-08"}, {time: "2023-06-09"}, {time: "2023-06-10"},…]
+        """
+
+        self._log = OutPutLog()
+        operate_mysql = OperateMysql(db="robotDataBase")
+        rovid = request['rovid']
+        month = request['month']
+
+        sql = f"SELECT DATE_FORMAT(createtime, '%Y-%m-%d') AS time FROM `rov1position` " \
+              f"WHERE `rovid`='{rovid}' AND `createtime` LIKE '{month}%' GROUP BY time;"
+        res = operate_mysql.execute_sql(sql)
+
+        return res
+
+

+ 32 - 0
005_H570/jikong_script/apis/robot_get_history_position_data.py

@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2023/06/13 09:37
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 返回机器人指定日期的坐标
+"""
+
+from abstract_api import AbstractApi
+from log import OutPutLog
+from apis.operate_mysql import OperateMysql
+
+
+class RobotGetHistoryPositionData(AbstractApi):
+
+    def operation(self, request):
+        """
+        返回机器人指定日期的坐标
+        @param request: {"rovid" : "xunjian1", "date": "2023-06-12"}
+        @return:[{time: "2023-06-08"}, {time: "2023-06-09"}, {time: "2023-06-10"},…]
+        """
+
+        self._log = OutPutLog()
+        operate_mysql = OperateMysql(db="robotDataBase")
+        rovid = request['rovid']
+        date = request['date']
+
+        sql = f"SELECT position_x AS x,position_y AS y,position_z AS z FROM `rov1position` WHERE `rovid`='{rovid}' AND `createtime` LIKE '{date}%' ORDER BY `createtime`;"
+        res = operate_mysql.execute_sql(sql)
+
+        return res

+ 30 - 0
005_H570/jikong_script/apis/robot_real_data.py

@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2023/06/12 16:20
+@Author: lxc
+@LastEditTime: 
+@Desctiption:返回机器人的实时数据
+"""
+
+
+from abstract_api import AbstractApi
+from log import OutPutLog
+from apis.operate_mysql import OperateMysql
+
+
+class RobotRealData(AbstractApi):
+
+    def operation(self, request):
+        self._log = OutPutLog()
+        operate_mysql = OperateMysql(db="robotDataBase")
+        rovid = request['rovid']
+
+        sql = f"SELECT storagetime,createtime,rovid,position_x,position_y,position_z,roll,pitch,yaw,voltage,depth " \
+              f"FROM `rov1position` " \
+              f"WHERE `rovid`='{rovid}' " \
+              f"ORDER BY `createtime` DESC LIMIT 1;"
+
+        res = operate_mysql.execute_sql(sql)
+
+        return res

+ 43 - 0
005_H570/jikong_script/apis/update_underwater_equip_clean_time.py

@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/9/24 11:12
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 更新水下设备的下次清洗时间
+"""
+
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from datetime import datetime, timedelta
+
+class UpdateUnderwaterEquipCleanTime(AbstractApi):
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+        device_name = request["device_name"]
+        status = request["status"]
+        if device_name == "all":
+            # 修改设备清洗提示功能的弹窗弹窗状态
+            update_sql = f"UPDATE underwater_equipment_clean SET function_status={status};"
+
+        else:
+            # 修改设备的下次清洗时间
+            select_sql = "SELECT clean_cycle,next_clean_time FROM underwater_equipment_clean WHERE device_name=\'%s\';" % (device_name)
+            device_info = operate_mysql.execute_sql(select_sql)[0]
+            if status == 1:
+                # 设备已清洗,修改本次清洗时间、下次清洗时间
+                this_clean_time = datetime.now()
+                clean_cycle = device_info["clean_cycle"]
+                next_clean_time = (this_clean_time+timedelta(days=clean_cycle)).strftime("%Y-%m-%d %H:%M:%S")
+                update_sql = "UPDATE underwater_equipment_clean SET this_clean_time=\'%s\',next_clean_time=\'%s\' WHERE device_name=\'%s\';" % (this_clean_time.strftime("%Y-%m-%d %H:%M:%S"), next_clean_time, device_name)
+
+            elif status == 0:
+                # 设备未清洗,4h后再次提示
+                next_clean_time = (datetime.now()+timedelta(hours=4)).strftime("%Y-%m-%d %H:%M:%S")
+                update_sql = "UPDATE underwater_equipment_clean SET next_clean_time=\'%s\' WHERE device_name=\'%s\'" % (next_clean_time, device_name)
+
+        res = operate_mysql.execute_sql(update_sql)
+        return res
+

+ 44 - 0
005_H570/jikong_script/apis/yuntaideng_change_mode.py

@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/30 16:53
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 修改 水下云台水下灯等设备定时开关 的相关信息
+"""
+
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+from log import OutPutLog
+import json
+
+class YuntaidengChangeMode(AbstractApi):
+
+    def operation(self, request):
+        self._log = OutPutLog()
+        operate_mysql = EventStorage()
+
+        device_name = request["device_name"]
+        control_mode = request["control_mode"]
+        sql = f"UPDATE shuixiayuntaideng_control SET control_mode={control_mode}"
+
+        if control_mode == 0:
+            # 手动控制模式
+            pass
+        elif control_mode == 1:
+            # 定时控制模式
+            definite_time = request["definite_time"]
+            time_list = []
+            for each_time in definite_time:
+                times = f"{each_time[0]},{each_time[1]}"
+                time_list.append(times)
+
+            definite_time = json.dumps(time_list)
+            sql = f"{sql}, definite_time=\'{definite_time}\'"
+
+        sql = f"{sql} WHERE device_name=\'{device_name}\';"
+        res = operate_mysql.execute_update_sql(sql)
+        if res is False:
+            self._log.error(f"水下云台灯控制模式修改失败!{sql}")
+
+        return res

+ 31 - 0
005_H570/jikong_script/apis/yuntaideng_get_mode.py

@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/30 16:53
+@Author: lxc
+@LastEditTime:
+@Desctiption: 获取 水下云台水下灯等设备定时开关 的相关信息
+"""
+
+import json
+from abstract_api import AbstractApi
+from event_storage import EventStorage
+
+class YuntaidengGetMode(AbstractApi):
+    """获取 水下云台水下灯等设备定时开关 的相关信息"""
+
+    def operation(self, request):
+        operate_mysql = EventStorage()
+
+        sql = "SELECT device_name,control_mode,definite_time FROM shuixiayuntaideng_control;"
+        datas = operate_mysql.execute_sql(sql)
+        for data in datas:
+            # {'device_name': 'shuixiayuntai01', 'control_mode': 1, 'definite_time': '[["06:00:00,07:59:59"]]\t'}
+            definite_time = json.loads(data["definite_time"])
+            time_dict = []
+            for each_time in definite_time:
+                t1, t2 = each_time.split(",")
+                time_dict.append([t1, t2])
+            data["definite_time"] = time_dict
+
+        return datas

+ 86 - 0
005_H570/jikong_script/auto_charge.py

@@ -0,0 +1,86 @@
+"""
+@Date  :2021/7/7/10:25
+@Author:zz
+@Desc  :自动启动发动机充电
+"""
+
+import time
+import json
+import threading
+
+from event_storage import EventStorage
+from utility import Utility
+from log import OutPutLog
+
+class AutoCharge:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+
+    # 历史存储主函数
+    def run(self):
+        self._log.info('[AutoCharge] - AutoFeeding module is running!')
+
+        # c101 蓄电池电压
+        # c402 主发运行
+        # c411 主发自动模式(0:本地模式,1:遥控模式,2:自动模式)
+        # c815 主发备车
+        # c423 应发运行
+        # c432 应发自动模式(0:本地模式,1:遥控模式,2:自动模式)
+        # c817 应发备车
+        list = ["c101", "c402", "c411", "c815", "c423", "c432", "c817"]
+
+        # 获取配置信息
+        while 1:
+            command = None
+            real_data_dict = self._storage.get_real_data(list)
+
+            sql_wind_light_configuration = "SELECT * FROM wind_light_configuration;"
+            wind_light_configuration = self._storage.execute_sql(sql_wind_light_configuration)
+
+            if wind_light_configuration is not None and len(wind_light_configuration) > 0:
+                charge_device = int(wind_light_configuration[0]['recharge_device_set'])                 # 充电设备配置 0:无;1:主发电机;2:应急发电机
+                charge_voltage = int(wind_light_configuration[0]['recharge_device_start_voltage'])      # 充电设备启动电压(V)
+                battery_voltage = real_data_dict['c101']       # 蓄电池电压
+
+                # 判断电池组电压是否低于设定电压
+                if battery_voltage is not None and int(battery_voltage) <= charge_voltage:
+                    # 判断是否有发电机正在运行
+                    if real_data_dict['c402'] != '1' and real_data_dict['c423'] != '1':
+
+                        if charge_device == 1 and real_data_dict['c402'] is not None and real_data_dict['c411'] is not None and real_data_dict['c815'] is not None:
+                            # 启用主发电机
+                            fdj_status = int(real_data_dict['c402'])
+                            fdj_mode = int(real_data_dict['c411'])
+                            fdj_beiche = int(real_data_dict['c815'])
+                            if fdj_status == 0 and fdj_mode == 2 and fdj_beiche == 1:
+                                command = {"device_id": 1, "start_addr": 3, "output_value": 65280, "function_code": 5, "res": 65280}
+                            else:
+                                print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {charge_device}设备(1=主发 2=应发)状态错误。当前模式为{fdj_mode},备车为{fdj_beiche}")
+                                self._log.error(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {charge_device}设备(1=主发 2=应发)状态错误。当前模式为{fdj_mode},备车为{fdj_beiche}")
+                        elif charge_device == 2 and real_data_dict['c423'] is not None and real_data_dict['c432'] is not None and real_data_dict['c817'] is not None:
+                            # 启动应急发电机
+                            fdj_status = int(real_data_dict['c423'])
+                            fdj_mode = int(real_data_dict['c432'])
+                            fdj_beiche = int(real_data_dict['c817'])
+                            if fdj_status == 0 and fdj_mode == 2 and fdj_beiche == 1:
+                                command = {"device_id": 1, "start_addr": 4, "output_value": 65280, "function_code": 5, "res": 65280}
+                            else:
+                                print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {charge_device}设备(1=主发 2=应发)状态错误。当前模式为{fdj_mode},备车为{fdj_beiche}")
+                                self._log.error(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {charge_device}设备(1=主发 2=应发)状态错误。当前模式为{fdj_mode},备车为{fdj_beiche}")
+            else:
+                print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} [AutoCharge]—参数获取失败")
+                self._log.info(f"{time.strftime('%Y-%m-%d %H:%M:%S')} [AutoCharge]—参数获取失败")
+
+
+            if command:
+                charge_connectors = Utility.available_connectors["remote_control"]
+                change_res = charge_connectors.send_command([command])
+                time.sleep(30)
+                if change_res:
+                    print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} 当前蓄电池组电压为{battery_voltage}V,低于{charge_voltage}V,启动{charge_device}设备(1=主发 2=应发)成功!")
+                else:
+                    print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} 当前蓄电池组电压为{battery_voltage}V,低于{charge_voltage}V,启动{charge_device}设备(1=主发 2=应发)失败!")
+                    self._log.error(f"{time.strftime('%Y-%m-%d %H:%M:%S')} 当前蓄电池组电压为{battery_voltage}V,低于{charge_voltage}V,启动{charge_device}设备(1=主发 2=应发)失败!")
+
+            time.sleep(10)

+ 313 - 0
005_H570/jikong_script/auto_feeding.py

@@ -0,0 +1,313 @@
+"""
+@Date  :2021/6/16/14:47
+@Author:zz
+@Desc  :投喂数据统计
+"""
+
+import time
+import json
+import threading
+
+from event_storage import EventStorage
+from utility import Utility
+from log import OutPutLog
+from apis.get_feeding_advise import GetFeedingAdvise
+
+
+class AutoFeeding:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+        self._run_time = None
+        self._run_timing = 0
+        self._feed_diameter = 0
+        self._error = 0
+
+    def t2s(self, t):
+        h, m = t.strip().split(":")
+        return int(h) * 3600 + int(m) * 60
+
+    # 历史存储主函数
+    def run(self):
+        self._log.info('[AutoFeeding] - AutoFeeding module is running!')
+        # c445:旋转输料器1号运行频率
+        # c446:旋转输料器2号运行频率
+        # c447:旋转输料器3号运行频率
+        # c448:旋转输料器4号运行频率
+        # c577:工作模式(0:手动模式, 1:自动模式)
+        # c578: 控制模式(0:远程控制,1:本地控制)
+        # c579:系统运行状态(1:自动投喂运行 2:自动投喂停止中3:自动投喂停止)
+        # c580:设备状态(0:未运行 1:手动运行中2:自动运行运行中)
+        # c854:分配器故障
+        # c855:分配器已使能
+        list = ["c445", "c446", "c447", "c448", "c577", "c578", "c579", "c580"]
+
+        # 获取配置信息
+        while 1:
+            time.sleep(1)
+            self._error = 0
+            real_data_dict = self._storage.get_real_data(list)
+            feeding_connectors = Utility.available_connectors["touwei"]
+            try:
+                device_status = int(real_data_dict["c580"])
+                system_status = int(real_data_dict["c579"])
+                system_mode = int(real_data_dict["c577"])
+                system_control_mode = int(real_data_dict["c578"])
+
+                # 自动投饵逻辑
+                feeder_frequency = 0        # 供料器频率
+                tank_number = 1
+                # 获取供料器频率及料罐信息
+                if float(real_data_dict['c445']) > 1:
+                    feeder_frequency = float(real_data_dict['c445'])
+                    tank_number = 1
+                elif float(real_data_dict['c446']) > 1:
+                    feeder_frequency = float(real_data_dict['c446'])
+                    tank_number = 2
+                elif float(real_data_dict['c447']) > 1:
+                    feeder_frequency = float(real_data_dict['c447'])
+                    tank_number = 3
+                elif float(real_data_dict['c448']) > 1:
+                    feeder_frequency = float(real_data_dict['c448'])
+                    tank_number = 4
+                sql_get_task_info = "SELECT * FROM touer_set;"
+                task_info = self._storage.execute_sql(sql_get_task_info)
+                task_info = task_info[0]
+                task_mode = int(task_info['feed_mode'])
+                # bait_name = tank_number_info['name']
+                # feed_weight = int(tank_number_info['weight'])
+                # shelf_life = tank_number_info['shelf_life']
+                tank_number_info = eval(task_info["tank" + str(tank_number)])
+                feed_diameter = int(tank_number_info['diameter'])       # 饵料直径
+
+                if feeder_frequency > 1:
+                    if self._run_time == None:
+                        self._run_time = time.time()
+                    feeding_speed = 1440 / 67 * feeder_frequency / 50 * (8 - 0.5 * feed_diameter) * 1 / 60
+                    now_time = time.time()
+                    self._run_timing = self._run_timing + (now_time - self._run_time)
+                    self._feed_diameter = self._feed_diameter + feeding_speed * (now_time - self._run_time)
+                    self._run_time = now_time
+                else:
+                    self._run_time = None
+                    self._run_timing = 0
+                    self._feed_diameter = 0
+                print("累计运行时间"+str(self._run_timing))
+            except Exception as e:
+                self._error = 1
+                print("get tank_number_info in AutoFeeding [ERROR]:" + str(e))
+                self._log.error("get tank_number_info in AutoFeeding [ERROR]:" + str(e))
+
+            # 通讯保护逻辑(呼吸脉搏)
+            if int(time.time()) % 10 == 0:
+                if int(time.time() / 10) % 2 == 0:
+                    print("1")
+                    feeding_connectors.send_command([{"addr_data": "DB2.DBX14.1", "data_type": "BOOL", "data": 1}])  # 保护置1
+                else:
+                    print("2")
+                    feeding_connectors.send_command([{"addr_data": "DB2.DBX14.1", "data_type": "BOOL", "data": 0}])  # 保护置0
+
+            if self._error == 0 and task_mode == 1:
+                # 获取投喂配置参数
+                sql_get_automatic_feeding_configuration = "SELECT * FROM automatic_feeding_configuration WHERE activation = 1;"
+                automatic_feeding_configuration = self._storage.execute_sql(sql_get_automatic_feeding_configuration)
+
+                # print(self._error)
+                # 自动投饵逻辑
+                if len(automatic_feeding_configuration) > 0:
+                    weekday = int(time.strftime('%w', time.localtime(time.time())))
+                    feedingAdvise = GetFeedingAdvise()
+                    feeding_port = feedingAdvise.operation(None)['port']
+                    # if feeding_port > 0:
+                    if 1:
+                        # print(feeding_port)
+                        for task in automatic_feeding_configuration:
+                            try:
+                                time_begin = self.t2s(task['time_begin'])
+                                time_end = int(task['time_end'])
+                                feeding_port_select = int(task['feeding_port'])
+                                feeding_line = int(task['feeding_line'])
+                                task_info = eval(task['phase_frequency'])
+                                feeder_frequency_set_stage1 = int(task_info['stage1']['frequency'])     # 供料器的三段频率
+                                feeder_frequency_set_stage2 = int(task_info['stage2']['frequency'])
+                                feeder_frequency_set_stage3 = int(task_info['stage3']['frequency'])
+                                time_stage1 = int(task_info['stage1']['time'])      # 三段不同频率分别对应的投饵时间
+                                time_stage2 = int(task_info['stage2']['time'])
+                                time_stage3 = int(task_info['stage3']['time'])
+                                feeding_amount_end = float(task['feeding_amount'])
+                                weekday_task = eval(task['date_bait'])
+                            except Exception as e:
+                                self._error = 1
+                                print(e)
+                                self._log.error("get tank_number_info in AutoFeeding [ERROR]:" + str(e))
+                            if self._error == 0:
+                                # 判断当日是否进行投饵
+                                if weekday_task.count(weekday) > 0:
+                                    # 判断是否到达开启时间,系统未运行,模式为投喂模式
+                                    time_now = time.strftime('%H:%M', time.localtime(time.time()))
+                                    time_now = self.t2s(time_now)
+                                    # 自动投饵操作
+                                    print("准备自动投饵")
+                                    # # 调试代码
+                                    # if time_begin == time_now:
+                                    #     # 开始投饵
+                                    #     print("开始投饵")
+                                    #
+                                    # if task['mode'] == "timing":
+                                    #     # 变频逻辑
+                                    #     if self._run_timing > time_stage1*60 and self._run_timing< time_stage2*60:
+                                    #         print("开始变频1")
+                                    #     elif self._run_timing > time_stage2*60 and self._run_timing < time_stage3*60:
+                                    #         print("开始变频2")
+                                    #     # 停止逻辑
+                                    #     if time_now == time_end:
+                                    #         print("停止")
+
+                                    # 获取选定路线对应的风机和供料器的地址
+                                    get_addr = self.feed_line_addr(feeding_line, feeding_port_select)
+                                    addr_GLQ = get_addr["addr_GLQ"]                 # 供料器的地址
+                                    addr_LCFJ = get_addr["addr_LCFJ"]               # 罗茨风机的地址
+                                    addr_start_line = get_addr["addr_start_line"]   # 线路的启动地址
+                                    addr_stop_line = get_addr["addr_stop_line"]     # 线路的停止地址
+                                    addr_line4_port = get_addr["addr_line4_port"]     # 线路4-x选择按钮的地址
+
+                                    print(time_begin, time_now, device_status, system_status, system_mode, system_control_mode, time_stage1, time_stage2, time_stage3)
+                                    if time_begin == time_now and system_mode == 1 and system_control_mode == 0:
+                                        # 开始投饵
+                                        print("开始投饵")
+                                        # if feeding_port_select > 0:
+                                        #     feeding_port = feeding_port_select
+                                        # feeding_connectors.send_command([{"addr_data": "DB14.DBX36.0","data_type": "UINT8","data": feeding_line}])  # 设置投饵线路
+                                        if feeding_line == 4:
+                                            feeding_connectors.send_command([{"addr_data": "DB14.DBX36.0", "data_type": "BOOL", "data": 1}])  # 使能开启
+                                            time.sleep(2)
+                                            real_data_dict1 = self._storage.get_real_data(["c854", "c855"])
+                                            fpq_guzhang = int(real_data_dict1["c854"])       # 分配器故障
+                                            fpq_enable = int(real_data_dict1["c855"])        # 分配器已使能
+                                            if fpq_guzhang == 0 and fpq_enable == 1:
+                                                feeding_connectors.send_command([{"addr_data": addr_line4_port, "data_type": "BOOL", "data": 1}])  # 设置线路4的投饵口,置1
+                                                print("设置线路4的投饵口,置1", addr_line4_port)
+                                                time.sleep(1)
+                                                feeding_connectors.send_command([{"addr_data": addr_line4_port, "data_type": "BOOL", "data": 0}])  # 设置线路4的投饵口,置0
+                                            else:
+                                                continue
+                                        # else:
+                                        #     continue
+                                        
+                                        print("开始设置频率")
+                                        feeding_connectors.send_command([{"addr_data": addr_GLQ, "data_type": "FLOAT32", "data": feeder_frequency_set_stage1}])  # 设置供料器频率
+                                        print("设置供料器频率", addr_GLQ, feeder_frequency_set_stage1)
+                                        feeding_connectors.send_command([{"addr_data": addr_LCFJ, "data_type": "FLOAT32", "data": 50}])  # 设置罗茨风机频率
+                                        print(" 设置罗茨风机频率", addr_LCFJ)
+
+                                        feeding_connectors.send_command([{"addr_data": addr_start_line, "data_type": "BOOL", "data": 1}])  # 启动置1
+                                        time.sleep(1)
+                                        feeding_connectors.send_command([{"addr_data": addr_start_line, "data_type": "BOOL", "data": 0}])  # 启动置0
+
+                                    if task['mode'] == "timing" and device_status == 2 and system_mode == 1 and system_control_mode == 0:
+                                        # 定时模式
+                                        if self._run_timing > time_stage1*60 and self._run_timing< time_stage2*60 and feeder_frequency_set_stage2 != int(feeder_frequency):
+                                            print("定时模式:开始变频1")
+                                            feeding_connectors.send_command([{"addr_data": addr_GLQ, "data_type": "FLOAT32", "data": feeder_frequency_set_stage2}])  # 设置供料器频率
+                                        elif self._run_timing > time_stage2*60 and self._run_timing < time_stage3*60 and feeder_frequency_set_stage3 != int(feeder_frequency):
+                                            print("定时模式:开始变频2")
+                                            feeding_connectors.send_command([{"addr_data": addr_GLQ, "data_type": "FLOAT32", "data": feeder_frequency_set_stage3}])  # 设置供料器频率
+                                        # 停止逻辑
+                                        if self._run_timing > time_end*60:
+                                            print("停止")
+                                            feeding_connectors.send_command([{"addr_data": addr_stop_line, "data_type": "BOOL", "data": 1}])   # 停止置1
+                                            time.sleep(1)
+                                            feeding_connectors.send_command([{"addr_data": addr_stop_line, "data_type": "BOOL", "data": 0}])   # 停止置0
+                                            if feeding_line == 4:
+                                                feeding_connectors.send_command([{"addr_data": "DB14.DBX36.0", "data_type": "BOOL", "data": 0}])  # 使能关闭
+
+
+                                    elif task['mode'] == "ration" and device_status == 2 and system_mode == 1 and system_control_mode == 0:
+                                        # print("开始定量模式", self._feed_diameter, time_stage1, time_stage2, feeder_frequency_set_stage2, feeder_frequency)
+                                        # 定量模式
+                                        # 变频逻辑
+                                        if self._feed_diameter > time_stage1 and self._feed_diameter < time_stage2 and feeder_frequency_set_stage2 != int(feeder_frequency):
+                                            print("定量模式:开始变频1")
+                                            feeding_connectors.send_command([{"addr_data": addr_GLQ, "data_type": "FLOAT32", "data": feeder_frequency_set_stage2}])  # 设置供料器频率
+                                        elif self._feed_diameter > time_stage2 and self._feed_diameter < time_stage3 and feeder_frequency_set_stage3 != int(feeder_frequency):
+                                            print("定量模式:开始变频2")
+                                            feeding_connectors.send_command([{"addr_data": addr_GLQ, "data_type": "FLOAT32", "data": feeder_frequency_set_stage3}])  # 设置供料器频率
+                                        # 停止逻辑
+                                        if self._feed_diameter > feeding_amount_end:
+                                            feeding_connectors.send_command([{"addr_data": addr_stop_line, "data_type": "BOOL", "data": 1}])   # 停止置1
+                                            time.sleep(1)
+                                            feeding_connectors.send_command([{"addr_data": addr_stop_line, "data_type": "BOOL", "data": 0}])   # 停止置0
+                                            if feeding_line == 4:
+                                                feeding_connectors.send_command([{"addr_data": "DB14.DBX36.0", "data_type": "BOOL", "data": 0}])  # 使能关闭
+                    else:
+                        if system_status == 1:
+                            print("停止")
+                            feeding_connectors.send_command([{"addr_data": addr_stop_line, "data_type": "BOOL", "data":1}])
+                            time.sleep(1)
+                            feeding_connectors.send_command([{"addr_data": addr_stop_line, "data_type": "BOOL", "data":0}])
+                            self._log.info('[AutoFeeding]—自然环境恶劣或系统存在异常,自动停止投饵!')
+                        else:
+                            self._log.info('[AutoFeeding]—自然环境恶劣或系统存在异常,无法执行自动投饵!')
+
+
+    def feed_line_addr(self, feeding_line, feeding_port):
+        """返回不同路线对应的风机和过滤器的地址"""
+        addr_P01 = "DB4.DBD0"
+        addr_P02 = "DB4.DBD4"
+        addr_P03 = "DB4.DBD8"
+        addr_P04 = "DB4.DBD12"
+        addr_GLQ01 = "DB4.DBD16"
+        addr_GLQ02 = "DB4.DBD20"
+        addr_GLQ03 = "DB4.DBD24"
+        addr_GLQ04 = "DB4.DBD28"
+        addr_start_line1 = "DB5.DBX12.2"
+        addr_start_line2 = "DB5.DBX12.3"
+        addr_start_line3 = "DB5.DBX12.4"
+        addr_start_line4 = "DB5.DBX12.5"
+        addr_stop_line1 = "DB5.DBX12.6"
+        addr_stop_line2 = "DB5.DBX12.7"
+        addr_stop_line3 = "DB5.DBX13.0"
+        addr_stop_line4 = "DB5.DBX13.1"
+        addr_line4_1 = "DB13.DBX0.4"
+        addr_line4_2 = "DB13.DBX0.5"
+        addr_line4_3 = "DB13.DBX0.6"
+        addr_line4_4 = "DB13.DBX0.7"
+
+        addr_line4_port = None
+        if feeding_line == 1:
+            addr_LCFJ = addr_P01
+            addr_GLQ = addr_GLQ01
+            addr_start_line = addr_start_line1
+            addr_stop_line = addr_stop_line1
+        elif feeding_line == 2:
+            addr_LCFJ = addr_P02
+            addr_GLQ = addr_GLQ02
+            addr_start_line = addr_start_line2
+            addr_stop_line = addr_stop_line2
+        elif feeding_line == 3:
+            addr_LCFJ = addr_P03
+            addr_GLQ = addr_GLQ03
+            addr_start_line = addr_start_line3
+            addr_stop_line = addr_stop_line3
+        elif feeding_line == 4:
+            addr_LCFJ = addr_P04
+            addr_GLQ = addr_GLQ04
+            addr_start_line = addr_start_line4
+            addr_stop_line = addr_stop_line4
+            if feeding_port == 1:
+                addr_line4_port = addr_line4_1
+            elif feeding_port == 2:
+                addr_line4_port = addr_line4_2
+            elif feeding_port == 3:
+                addr_line4_port = addr_line4_3
+            elif feeding_port == 4:
+                addr_line4_port = addr_line4_4
+
+        res_dict = {
+            "addr_LCFJ": addr_LCFJ,
+            "addr_GLQ": addr_GLQ,
+            "addr_start_line": addr_start_line,
+            "addr_stop_line": addr_stop_line,
+            "addr_line4_port": addr_line4_port
+        }
+        return res_dict

+ 84 - 0
005_H570/jikong_script/auto_profile_1501.py

@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/08/23 14:53
+@Author: lxc
+@LastEditTime: 
+@Desctiption: sct1501的PLC自动开关剖面功能:根据单点流速仪中的流速数值判断,大于0.3m/s时停止剖面,小于等于0.3m/s时开始剖面
+"""
+
+
+from event_storage import EventStorage
+from log import OutPutLog
+import time
+from datetime import datetime
+from utility import Utility
+
+
+class AutoProfile1501:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+
+
+    def run(self):
+        self._log.info("[AutoSwitchDevice] - AutoSwitchDevice module is running!")
+        # c7:单点流速仪:流速(cm/s)
+        # c88:PLC剖面功能(0=未开启,1=开启)
+        self.point_list = ["c7", "c88"]
+        run_time = 0
+        while True:
+            this_time = time.time()
+            if this_time - run_time > 60:
+                run_time = this_time
+                self.now_time = datetime.now().strftime("%Y-%m-%d %H:%M:%M")
+
+                real_data_dict = self._storage.get_real_data(self.point_list)
+                flow_speed = real_data_dict['c7']
+                profile_status = real_data_dict['c88']
+                print(f"{self.now_time} [AutoProfile1501]: {flow_speed} {profile_status}")
+
+                if flow_speed is None or profile_status is None:
+                    print(f"{self.now_time} [AutoProfile1501]: 参数读取失败,当前流速为{flow_speed}cm/s, 剖面状态为{profile_status}(0=关闭,1=开启)")
+                else:
+                    flow_speed = float(flow_speed)
+                    profile_status = int(profile_status)
+                    if flow_speed > 0.3 and profile_status == 1:
+                        # 流速大于0.3m/s时且正在剖面中,停止剖面
+                        print(f"{self.now_time} [AutoProfile1501]: 当前流速为{flow_speed}cm/s, 停止剖面")
+                        self.control_device(station_name="sct1501", device_id=1, start_addr=3142, output_value=0, function_code=5)
+                    elif 0 <= flow_speed <= 0.3 and profile_status == 0:
+                        # 流速小于等于0.3m/s时且没有开启剖面,开启剖面
+                        print(f"{self.now_time} [AutoProfile1501]: 当前流速为{flow_speed}cm/s, 开启剖面")
+                        self.control_device(station_name="sct1501", device_id=1, start_addr=3142, output_value=1, function_code=5)
+
+    def control_device(self, station_name, device_id, start_addr, output_value, function_code):
+        """给设备发送指令"""
+        command = [{"device_id": device_id, "start_addr": start_addr, "output_value": output_value, "function_code": function_code}]
+        status = True
+        t1 = time.time()
+        while status:
+            try:
+                time.sleep(2)
+                Utility.available_connectors[station_name].send_command(command)
+                # 判断剖面状态是否修改成功
+                real_data_dict = self._storage.get_real_data(self.point_list)
+                flow_speed = real_data_dict['c7']
+                profile_status = real_data_dict['c88']
+
+                if flow_speed is None or profile_status is None:
+                    print(f"{self.now_time} [AutoProfile1501]: 修改剖面状态失败(参数读取失败): 当前流速为{flow_speed}cm/s, 剖面状态为{profile_status}(0=关闭,1=开启)")
+                else:
+                    flow_speed = float(flow_speed)
+                    profile_status = int(profile_status)
+                    if profile_status == output_value:
+                        print(f"{self.now_time} [AutoProfile1501]: 修改剖面状态成功,当前流速为{flow_speed}cm/s, 当前剖面状态为{profile_status}(0=关闭,1=开启)!")
+                        status = False
+                        
+            except Exception as e:
+                print(f"{self.now_time} [AutoProfile1501]: {e}")
+
+            finally:
+                if time.time() - t1 >= 60:
+                    print(f"{self.now_time} [AutoProfile1501]: 修改剖面状态失败!")
+                    status = False

+ 126 - 0
005_H570/jikong_script/auto_switch_device.py

@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/10/13 10:58
+@Author: lxc
+@LastEditTime:
+@Desctiption: 实现设备定时开关功能,实时更新设备当前状态
+"""
+
+
+from event_storage import EventStorage
+from log import OutPutLog
+import time
+from datetime import datetime
+from utility import Utility
+import json
+
+class AutoSwitchDevice:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+
+    def run(self):
+        self._log.info("[AutoSwitchDevice] - AutoSwitchDevice module is running!")
+        run_time = 0
+        while True:
+            this_time = time.time()
+            if this_time - run_time > 10:
+                run_time = this_time
+
+                # 获取设备的当前状态
+                device_real_status = self.update_device_status()
+                # print("-------------------------------", device_real_status)
+
+                get_auto_switch_device = "SELECT device_name,open_time,close_time,open_command,close_command FROM auto_switch_device WHERE status=1;"
+                auto_switch_device = self._storage.execute_sql(get_auto_switch_device)
+                if len(auto_switch_device) > 0:
+                    now_time = datetime.now().strftime("%H:%M:%S")
+                    for each_device in auto_switch_device:
+                        device_name = each_device["device_name"]
+                        open_time = datetime.strptime(str(each_device["open_time"]), '%H:%M:%S').strftime("%H:%M:%S")
+                        close_time = datetime.strptime(str(each_device["close_time"]), '%H:%M:%S').strftime("%H:%M:%S")
+
+                        device_status = 0       # 默认设备是关闭状态
+                        # 判断当前时间设备应该设置的状态
+                        if open_time > close_time:
+                            if close_time < now_time < open_time:
+                                pass
+                            else:
+                                device_status = 1
+                        else:
+                            if open_time < now_time < close_time:
+                                device_status = 1
+                            else:
+                                pass
+
+                        device_command = None
+                        # 获取设备应该设置的状态的指令
+                        if device_status == 0:
+                            device_command = each_device["close_command"]
+                        elif device_status == 1:
+                            device_command = each_device["open_command"]
+
+                        # 与当前实际状态比较
+                        if device_name in device_real_status.keys() and device_real_status[device_name] == device_status:
+                            device_command = None
+
+                        # 发送命令
+                        if device_command:
+                            device_command = device_command.split(",")
+                            # print("***********************",device_name, device_command)
+                            for each_command in device_command:
+
+                                # print(device_name, device_command)
+                                # command = bytes.fromhex(device_command).decode()
+                                # command = bytes.fromhex(each_command)
+                                try:
+                                    Utility.available_connectors[device_name].send_command({"size": 15, "command": each_command})
+                                except Exception as e:
+                                    print(each_command + "write[ERROR]:" + str(e))
+                else:
+                    print("所有设备无需开启定时模式!")
+
+                self.update_device_status()
+
+
+
+    def auto_update_device_status(self):
+        """自动更新水下云台灯的状态"""
+        run_time = 0
+        while True:
+            this_time = time.time()
+            if this_time - run_time > 2:
+                run_time = this_time
+                self.update_device_status()
+
+
+    def update_device_status(self):
+        """获取水下云台水下灯的最新状态"""
+        get_status_command_sql = "SELECT device_name, status_command, IO FROM auto_switch_device;"
+        get_status_command = self._storage.execute_sql(get_status_command_sql)
+        device_real_status = {}
+        if len(get_status_command) > 0:
+            for each in get_status_command:
+                device_name = each["device_name"]
+                status_command = each["status_command"]
+                IO = each["IO"]
+                subscript = 8 + (int(IO) - 1) * 2
+                # status_command = bytes.fromhex(status_command)
+                try:
+                    res_status_command = Utility.available_connectors[device_name].send_command({"size": 15, "command": status_command})
+                    if res_status_command:
+                        res_status = res_status_command.hex()[subscript:subscript + 2]
+                        if res_status == "01":
+                            light_status = 1
+                        elif res_status == "00":
+                            light_status = 0
+                        else:
+                            light_status = None
+                        device_real_status[device_name] = light_status
+                        update_sql = f"UPDATE auto_switch_device SET light_status={light_status} WHERE device_name=\'{device_name}\';"
+                        self._storage.execute_update_sql(update_sql)
+                except Exception as e:
+                    print(f"{device_name} {status_command} write[ERROR]: {e}")
+
+        return device_real_status

+ 266 - 0
005_H570/jikong_script/auto_switch_juyudeng.py

@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/28 18:53
+@Author: lxc
+@LastEditTime:
+@Desctiption: 聚鱼灯
+"""
+
+from event_storage import EventStorage
+from log import OutPutLog
+import time
+from datetime import datetime
+from utility import Utility
+import json
+
+
+class AutoSwitchJuyudeng:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+
+    def run(self):
+        self._log.info("[AutoSwitchDevice] - AutoSwitchDevice module is running!")
+        run_time = 0
+        while True:
+            this_time = time.time()
+            self.now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+            if this_time - run_time > 60:
+                run_time = this_time
+
+                self.check_status()
+                self.update_juyudeng_status()
+
+
+    def get_light_real_status(self):
+        """
+        获取聚鱼灯的实时状态:光敏模式的状态、灯的开关状态
+        :return: {'juyudeng_1#_guangmin': 0, 'juyudeng_2#_guangmin': 1, 'juyudeng_3#_guangmin': 0,
+        'juyudeng_4#_guangmin': 0, 'juyudeng_5#_guangmin': 0, 'juyudeng_6#_guangmin': 1, 'juyudeng_7#_guangmin': 1,
+        'juyudeng_8#_guangmin': 1, 'juyudeng_1#_status': 1, 'juyudeng_2#_status': 1, 'juyudeng_3#_status': 0,
+        'juyudeng_4#_status': 0, 'juyudeng_5#_status': 1, 'juyudeng_6#_status': 1, 'juyudeng_7#_status': 0,
+        'juyudeng_8#_status': 0}
+        """
+
+        sql_point_info = "SELECT serial_number,io_point_name " \
+                         "FROM `data_point_tbl` " \
+                         "WHERE `io_point_name` LIKE 'juyudeng_%_%';"
+        point_info = self._storage.execute_sql(sql_point_info)
+
+        read_real_list = []
+        point_name_dict = {}
+        for each in point_info:
+            serial_number = "c"+str(each["serial_number"])
+            read_real_list.append(serial_number)
+            point_name_dict[serial_number] = each["io_point_name"]
+        real_data_dict = self._storage.get_real_data(read_real_list)
+
+        light_real_status = {}
+        for k, v in real_data_dict.items():
+            light_real_status[point_name_dict[k]] = v
+
+        return light_real_status
+
+
+    def get_light_his_status(self):
+        """
+        获取聚鱼灯的历史状态信息
+        :return: [{'location': '1#', 'control_mode': 1, 'status': 1, 'definite_time': '[]',
+        'commands': '{"open_light": [{"res": 65280, "device_id": 1, "start_addr": 0, "output_value": 65280, "function_code": 5},
+        {"res": 65280, "device_id": 1, "start_addr": 1, "output_value": 65280, "function_code": 5}],
+        "close_light": [{"res": 0, "device_id": 1, "start_addr": 0, "output_value": 0, "function_code": 5},
+        {"res": 0, "device_id": 1, "start_addr": 1, "output_value": 0, "function_code": 5}],
+        "open_photosense": [{"res": 0, "device_id": 1, "start_addr": 2, "output_value": 0, "function_code": 5}],
+        "close_photosense": [{"res": 65280, "device_id": 1, "start_addr": 2, "output_value": 65280, "function_code": 5}]}',
+        'conn_status': 1}, ...]
+        """
+
+        sql_his_info = "SELECT location,control_mode,status,definite_time,commands,conn_status " \
+                       "FROM `gather_fish_light_control`;"
+        his_info = self._storage.execute_sql(sql_his_info)
+
+        return his_info
+
+
+
+    def check_status(self):
+
+        # 获取聚鱼灯的实时状态:光敏模式的状态、灯的开关状态
+        light_real_status = self.get_light_real_status()
+        print("light_real_status=", light_real_status)
+
+        # 获取聚鱼灯的历史状态信息
+        light_his_status = self.get_light_his_status()
+
+        for each in light_his_status:
+            # {'location': '2#', 'control_mode': 1, 'status': 1, 'definite_time': '[["00:00:00,23:59:59"]]', 'commands': '{}', 'conn_status': 0}
+
+            location = each['location']                 # 聚鱼灯的位置
+            his_control_mode = each['control_mode']     # 历史控制模式(0=光敏控制 1=手动控制 2=定时控制)
+            his_status = each['status']                 # 历史状态(0=关 1=开,模式1需要获取该参数的值)
+            his_conn_status = each['conn_status']       # 历史通讯状态(0=在线,1=不在线)
+            command = json.loads(each['commands'])                  # 控制开关的指令
+            guangmin_status = light_real_status[f"juyudeng_{location}_guangmin"]    # 此刻光敏模式的状态(0=开 1=关)
+            light_status = light_real_status[f"juyudeng_{location}_status"]         # 此刻灯的状态(0=关 1=开)
+
+            sql_update = False
+            all_command = []
+            # 对比现在的状态和断电之前的状态
+            try:
+                if light_status is not None and his_conn_status == 1:
+                    # 现在能读到聚鱼灯的状态且上一次读不到:将聚鱼灯的状态恢复至断电之前的状态,更新conn_status的状态
+                    print(f"{self.now}-[check_status]-{location}聚鱼灯 ({light_status},{light_status},{guangmin_status},0) 1、2路表示灯开关(0关 1开) 3路表示光敏模式开关(0开 1关)")
+                    if his_control_mode == 0:
+                        # 恢复至光敏模式
+                        if int(guangmin_status) == 1:
+                            # 当前是非光敏模式,需要改为光敏模式
+                            if light_status == 1:
+                                # 先关灯
+                                all_command.extend(command['close_light'])
+                                print(f"{self.now}-[check_status]-{location}聚鱼灯 先关灯,再设为光敏模式")
+                            # 再开光敏
+                            all_command.extend(command['open_photosense'])
+                            print(f"{self.now}-[check_status]-{location}聚鱼灯 设为光敏模式")
+                        else:
+                            # 当前是光敏模式,不需要处理
+                            # print(f"{self.now}-[check_status]-{location}聚鱼灯 当前是光敏模式,不需要处理")
+                            pass
+                    elif his_control_mode == 1:
+                        # 恢复至手动模式
+                        if int(guangmin_status) == 0:
+                            # 先关闭光敏模式
+                            all_command.extend(command['close_photosense'])
+                            print(f"{self.now}-[check_status]-{location}聚鱼灯 先关闭光敏模式,再修改灯的状态为{his_status}")
+                        if light_status != his_status:
+                            # 聚鱼灯改为his_status的状态(0=关 1=开)
+                            if his_status == 0:
+                                all_command.extend(command['close_light'])
+                            elif his_status == 1:
+                                all_command.extend(command['open_light'])
+                            print(f"{self.now}-[check_status]-{location}聚鱼灯 修改灯的状态为{his_status}")
+                        else:
+                            # print(f"{self.now}-[check_status]-{location}聚鱼灯 状态相同{his_status},不需要处理")
+                            pass
+                    elif his_control_mode == 2:
+                        # 恢复至定时模式
+                        if int(guangmin_status) == 0:
+                            # 先关闭光敏模式
+                            all_command.extend(command['close_photosense'])
+                            print(f"{self.now}-[check_status]-{location}聚鱼灯 定时模式:先关闭光敏模式")
+                        # 判断开关灯在 command_polling 方法中
+
+                    # 更新conn_status的状态
+                    sql_update = f"UPDATE `gather_fish_light_control` SET conn_status=0 WHERE `location`='{location}';"
+                elif light_status is None and his_conn_status == 0:
+                    # 现在读不到聚鱼灯的状态且上一次能读到:更新conn_status的状态
+                    sql_update = f"UPDATE `gather_fish_light_control` SET conn_status=1 WHERE location='{location}';"
+
+                elif light_status is None and his_conn_status == 1:
+                    # print(f"{self.now}-[check_status]-{location}聚鱼灯一直处于离线状态,不做处理")
+                    pass
+
+                elif light_status is not None and his_conn_status == 0:
+                    # 聚鱼灯一直处于在线状态
+                    if int(his_status) == int(light_status):
+                        # print(f"{self.now}-[check_status]-{location}聚鱼灯一直处于在线状态,status与当前状态一致!")
+                        pass
+                    else:
+                        # 更新status字段的状态(control_mode字段的状态由前端调接口修改)
+                        sql_update = f"UPDATE `gather_fish_light_control` SET status={light_status} WHERE `location`='{location}';"
+                        print(f"{self.now}-[check_status]-{location}聚鱼灯一直处于在线状态,保存当前模式status={light_status}")
+
+
+                # 执行修改状态的指令
+                if len(all_command) > 0:
+                    jyd_connectors = Utility.available_connectors[f"juyudeng_{location}"]
+                    for each_command in all_command:
+                        print(f"{self.now}-[check_status]-{location}聚鱼灯 {each_command}")
+                        jyd_connectors.send_command(each_command)
+
+                if sql_update:
+                    print(f"{self.now}-[check_status]-{location}聚鱼灯 {sql_update}")
+                    self._storage.execute_update_sql(sql_update)
+            except Exception as e:
+                print(f"{self.now}-[check_status]-{location}聚鱼灯 ERROR:{e}")
+                self._log.error(e)
+
+
+
+    def get_real_status(self):
+        """
+        获取聚鱼灯的实时状态
+        return:{'juyudeng_1#': '1', 'juyudeng_2#': None, 'juyudeng_3#': None,...}
+        """
+        juyudeng_point_sql = "SELECT serial_number,io_point_name FROM `data_point_tbl` WHERE `io_point_name` LIKE 'juyudeng_%_status';"
+        juyudeng_point = self._storage.execute_sql(juyudeng_point_sql)
+        read_real_list = []
+        point_name_dict = {}
+        for each in juyudeng_point:
+            serial_number = "c"+str(each["serial_number"])
+            read_real_list.append(serial_number)
+            juyudeng_name = each["io_point_name"].replace("_status", "")
+            point_name_dict[serial_number] = juyudeng_name
+        real_data_dict = self._storage.get_real_data(read_real_list)
+
+        light_real_status = {}
+        for k,v in real_data_dict.items():
+            light_real_status[point_name_dict[k]] = v
+
+        return light_real_status
+
+
+    def update_juyudeng_status(self):
+        """判断聚鱼灯的状态是否需要修改"""
+        # 获取聚鱼灯的实时状态
+        all_light_real_status = self.get_real_status()      # {'juyudeng_1#': '1', 'juyudeng_2#': None,...}
+        # print(all_light_real_status)
+
+        # 判断聚鱼灯的状态是否需要修改
+        juyudeng_info_sql = "SELECT location,control_mode,definite_time,commands FROM `gather_fish_light_control`;"
+        get_juyudeng_info = self._storage.execute_sql(juyudeng_info_sql)
+        for juyudeng_info in get_juyudeng_info:
+            # {'location': '1#', 'control_mode': 0, 'definite_time': '[["06:00:00,10:59:59"], ["00:03:00,03:50:59"]]', 'commands': None}
+            control_mode = juyudeng_info["control_mode"]     # 0:光敏控制,1:手动控制,2:定时控制
+
+            if control_mode == 0:
+                '''光敏模式:前端发送控制指令'''
+                pass
+            elif control_mode == 1:
+                '''手动模式:前端发送控制指令'''
+                pass
+            elif control_mode == 2:
+                '''定时模式'''
+                light_status = 0        # 默认聚鱼灯处于关闭状态
+                now_time = datetime.now().strftime("%H:%M:%S")
+                definite_time = json.loads(juyudeng_info["definite_time"])
+                # 依次判断每个时间段
+                for time_list in definite_time:
+                    each_time = time_list[0].split(",")
+                    time1 = each_time[0]
+                    time2 = each_time[1]
+                    if time1 < time2:
+                        if time1 <= now_time <= time2:
+                            light_status = 1
+                    else:
+                        if time2 <= now_time <= time1:
+                            light_status = 1
+                # 判断是否需要修改当前状态
+                light_name = f"juyudeng_{juyudeng_info['location']}"
+                light_real_status = all_light_real_status[light_name]
+                # print("///////////////////////",light_name, light_real_status, light_status)
+
+                if light_real_status is None or int(light_status) != int(light_real_status):
+                    commands = json.loads(juyudeng_info["commands"])
+                    if int(light_status) == 0:
+                        # 关灯
+                        command = commands["close_light"]
+                    elif int(light_status) == 1:
+                        # 开灯
+                        command = commands["open_light"]
+                    # print(light_name, light_real_status. light_status, command)
+
+                    try:
+                        Utility.available_connectors[light_name].send_command(command)
+                    except Exception as e:
+                        self._log.error(e)

+ 112 - 0
005_H570/jikong_script/auto_switch_yuntaideng.py

@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/10/13 10:58
+@Author: lxc
+@LastEditTime:
+@Desctiption: 水下云台灯
+"""
+
+
+from event_storage import EventStorage
+from log import OutPutLog
+import time
+from datetime import datetime
+from utility import Utility
+import json
+
+class AutoSwitchYuntaideng:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+
+    def run(self):
+        self._log.info("[AutoSwitchDevice] - AutoSwitchDevice module is running!")
+        run_time = 0
+        while True:
+            this_time = time.time()
+            if this_time - run_time > 60:
+                run_time = this_time
+
+                self.update_yuntaideng_status()
+
+
+    def get_real_status(self):
+        """
+        获取水下云台灯的实时状态
+        return:{'shuixiayuntai01': '1', 'shuixiayuntai02': None, 'shuixiayuntai03': None,...}
+        """
+        juyudeng_point_sql = "SELECT serial_number,io_point_name FROM `data_point_tbl` WHERE `io_point_name` LIKE 'shuixiayuntai%_status';"
+        juyudeng_point = self._storage.execute_sql(juyudeng_point_sql)
+        read_real_list = []
+        point_name_dict = {}
+        for each in juyudeng_point:
+            serial_number = "c"+str(each["serial_number"])
+            read_real_list.append(serial_number)
+            juyudeng_name = each["io_point_name"].replace("_status", "")
+            point_name_dict[serial_number] = juyudeng_name
+        real_data_dict = self._storage.get_real_data(read_real_list)
+
+        light_real_status = {}
+        for k,v in real_data_dict.items():
+            light_real_status[point_name_dict[k]] = v
+
+        return light_real_status
+
+
+    def update_yuntaideng_status(self):
+        """判断水下云台灯的状态是否需要修改"""
+
+        # # 获取水下云台灯的实时状态
+        # all_light_real_status = self.get_real_status()      # {'shuixiayuntai01': '0', 'shuixiayuntai02': None, 'shuixiayuntai03': None, 'shuixiayuntai04': None}
+        # #print(all_light_real_status)
+
+        # 判断水下云台灯的状态是否需要修改
+        yuntaideng_info_sql = "SELECT device_name,control_mode,definite_time,commands FROM `shuixiayuntaideng_control`;"
+        get_yuntaideng_info = self._storage.execute_sql(yuntaideng_info_sql)
+
+        for yuntaideng_info in get_yuntaideng_info:
+            # {'device_name': 'shuixiayuntai01', 'control_mode': 0, 'definite_time': '[["06:00:00,07:59:59"]]\t', 'commands': '[{"open_command": "AA 88 01 00 55", "close_command": "AA 88 01 01 55"}]'}
+            control_mode = yuntaideng_info["control_mode"]     # 0:手动模式,1:定时模式
+
+            if control_mode == 0:
+                '''手动模式:前端发送控制指令'''
+                pass
+            elif control_mode == 1:
+                '''定时模式'''
+                light_status = 0        # 默认水下云台灯处于关闭状态
+                now_time = datetime.now().strftime("%H:%M:%S")
+                definite_time = json.loads(yuntaideng_info["definite_time"])
+                # 依次判断每个时间段
+                for time_list in definite_time:
+                    each_time = time_list.split(",")
+                    time1 = each_time[0]
+                    time2 = each_time[1]
+                    if time1 < time2:
+                        if time1 <= now_time <= time2:
+                            light_status = 1
+                    else:
+                        if time2 <= now_time <= time1:
+                            light_status = 1
+
+
+                # 判断是否需要修改当前状态
+                light_name = yuntaideng_info['device_name']
+                # light_real_status = all_light_real_status[light_name]
+                #
+                # if light_real_status is None or int(light_status) != int(light_real_status):
+                commands = json.loads(yuntaideng_info["commands"])
+
+                for each_command in commands:
+                    if int(light_status) == 0:
+                        # 关灯
+                        command = each_command["close_command"]
+                    elif int(light_status) == 1:
+                        # 开灯
+                        command = each_command["open_command"]
+                    # print("--------------",light_name, light_real_status, light_status, command)
+                    try:
+                        Utility.available_connectors[light_name].send_command(command)
+                    except Exception as e:
+                        print("----------------", light_name, e)
+                        self._log.error(e)

+ 18 - 0
005_H570/jikong_script/config.json

@@ -0,0 +1,18 @@
+{
+  "hardDiskdataBase":{
+    "ip": "127.0.0.1",
+    "username": "root",
+    "password": "R.!a@O&t9CjweWLSTr",
+    "dataBaseName": "centralized_control_db"
+  },
+  "memoryDatabase": {
+    "ip": "127.0.0.1",
+    "port": 6379
+  },
+    "robotDataBase":{
+    "ip": "127.0.0.1",
+    "username": "root",
+    "password": "R.!a@O&t9CjweWLSTr",
+    "dataBaseName": "rovdb"
+  }
+}

+ 32 - 0
005_H570/jikong_script/configuration.py

@@ -0,0 +1,32 @@
+import json
+import os
+import sys
+
+
+class Configuration:
+    def __init__(self):
+        # self.system_config = self.get_system_config()
+        pass
+
+    def get_system_config(self):
+        """"读取配置"""
+        if sys.platform == 'win32':
+            # config_file_path = os.path.dirname(os.path.realpath(sys.argv[0])) + r'\config.json'
+            config_file_path = r'.\config.json'
+        elif sys.platform == 'linux':
+            config_file_path = 'config.json'
+        with open(config_file_path) as json_file:
+            config = json.load(json_file)
+        return config
+
+    def set_config(self):
+        pass
+
+    def add_device(self):
+        pass
+
+    def delete_device(self):
+        pass
+
+    def updata_device(self):
+        pass

+ 31 - 0
005_H570/jikong_script/connector.py

@@ -0,0 +1,31 @@
+import logging
+from abc import ABC, abstractmethod
+
+log = logging.getLogger("connector")
+
+
+class Connector(ABC):
+
+    @abstractmethod
+    def open(self):
+        pass
+
+    @abstractmethod
+    def close(self):
+        pass
+
+    @abstractmethod
+    def get_name(self):
+        pass
+
+    @abstractmethod
+    def is_connected(self):
+        pass
+
+    @abstractmethod
+    def send_command(self, content):
+        pass
+
+    @abstractmethod
+    def command_polling(self, content):
+        pass

+ 10 - 0
005_H570/jikong_script/connectors/__init__.py

@@ -0,0 +1,10 @@
+from . import modbus_rtu_over_tcp_connector
+from . import modbus_moxae1210_connector
+from . import http_connector
+from . import siemens_plc_s7_connector
+from . import melsec_plc_a1e_connector
+from . import tcp_connector
+from . import gather_fish_light_connector
+from . import modbus_rtu_over_tcp_normal
+from . import modbus_tcp_connector
+from . import siemens_plc_s7_s200smart_connector

+ 341 - 0
005_H570/jikong_script/connectors/gather_fish_light_connector.py

@@ -0,0 +1,341 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/12/8 14:57
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 聚鱼灯的连接器,控制聚鱼灯的开关
+"""
+
+import json
+import threading
+from connector import Connector
+from event_storage import EventStorage
+from log import OutPutLog
+import time
+import datetime
+from modbus_tk import modbus_rtu_over_tcp
+
+
+class GatherFishLightConnector(Connector, threading.Thread):
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self._master = None
+        self.__stopped = False
+        self._connected = False
+        self._ip = config['ip']  # ip
+        self._port = config['port']  # 端口
+        self._converter = converter
+        self._storager = EventStorage()
+        self._name = name
+        self.run_time = 0
+        self._command = json.loads(self._storager.get_command_info(name[:-3])[0]["command"])
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+
+    def run(self):
+        self._connect()
+        self._connected = True
+
+        while True:
+            this_time = time.time()
+            if this_time - self.run_time > 5:
+                self.run_time = this_time
+
+                light_info = self._storager.gather_fish_light_info(self._name[-2:])
+                for each_light in light_info:
+                    self.command_polling(each_light)
+
+
+    def _connect(self):
+        try:
+            self._master = modbus_rtu_over_tcp.RtuOverTcpMaster(host=self._ip, port=self._port)
+            print(f"{self._ip}:{self._port} connect success!")
+        except Exception as e:
+            print(f"{self._ip}:{self._port} connect failed!")
+            self._log.error(f"{self._ip}:{self._port} connect failed! {e}")
+            self._connected = False
+            self._reconnect()
+
+
+    def _reconnect(self):
+        while True:
+            try:
+                self._master = modbus_rtu_over_tcp.RtuOverTcpMaster(host=self._ip, port=self._port)
+                print(f"{self._ip}:{self._port} reconnect success!")
+                print('client start connect to host/port:{}'.format(self._port))
+                break
+            except ConnectionRefusedError:
+                print(f"{self._ip}:{self._port} modbus server refused or not started, reconnect to server in 5s .... ")
+                time.sleep(5)
+            except Exception as e:
+                print(f"{self._ip}:{self._port} reconnect failed!")
+                self._log.error(f"{self._ip}:{self._port} reconnect failed! {e}")
+                time.sleep(5)
+
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self._connected
+
+    def send_command(self, data):
+
+        result = True
+        try:
+            for each_command in data:
+                result = self.exec_command(each_command)
+        except Exception as e:
+            print(f"[GatherFishLightConnector][send_command] error: {e}")
+            result = False
+        print("------[FishLight send_command]", self._ip, data, result)
+        return result
+
+
+    def exec_command(self, command):
+        """
+        0x01: 读线圈寄存器
+        0x02: 读离散输入寄存器
+        0x03: 读保持寄存器
+        0x04: 读输入寄存器
+        0x05: 写单个线圈寄存器
+        0x06: 写单个保持寄存器
+        0x0f: 写多个线圈寄存器
+        0x10: 写多个保持寄存器
+        #supported modbus functions
+        READ_COILS = 1
+        READ_DISCRETE_INPUTS = 2
+        READ_HOLDING_REGISTERS = 3
+        READ_INPUT_REGISTERS = 4
+        WRITE_SINGLE_COIL = 5
+        WRITE_SINGLE_REGISTER = 6
+        READ_EXCEPTION_STATUS = 7
+        DIAGNOSTIC = 8
+        REPORT_SLAVE_ID = 17
+        WRITE_MULTIPLE_COILS = 15
+        WRITE_MULTIPLE_REGISTERS = 16
+        READ_WRITE_MULTIPLE_REGISTERS = 23
+        DEVICE_INFO = 43
+        """
+        if isinstance(command, str):
+            command = json.loads(command)
+        device_id = int(command['device_id'])
+        function_code = int(command['function_code'])
+        start_addr = int(command['start_addr'])
+        output_value = command['output_value']
+
+        if function_code in (1, 2, 3, 4):
+            # 读寄存器
+            pass
+        elif function_code in (5, 6, 15, 16):
+            # 写寄存器
+            try:
+                self._master.set_timeout(10.0)
+                self._master.set_verbose(True)
+                # print("device_id = ", device_id,  function_code, start_addr, output_value)
+                data = self._master.execute(device_id, function_code, start_addr, output_value=output_value)
+                res = command["res"]
+                result = False
+                if function_code == 5:
+                    if start_addr == data[0] and res == data[1]:
+                        result = True
+                time.sleep(1)
+                return result
+            except Exception as e:
+                self._log.error(e)
+                return False
+        else:
+            self._log.debug(f'Unsupported function code.')
+
+        # """
+        # {
+        #     "light_0": [
+        #         {"res": 65280, "device_id": 1, "start_addr": 0, "output_value": 255, "function_code": 5},
+        #         {"res": 65280, "device_id": 1, "start_addr": 1, "output_value": 255, "function_code": 5}
+        #     ],
+        #     "light_1": [
+        #         {"res": 0, "device_id": 1, "start_addr": 0, "output_value": 0, "function_code": 5},
+        #         {"res": 0, "device_id": 1, "start_addr": 1, "output_value": 0, "function_code": 5}
+        #     ],
+        #     "photosense_0": [
+        #         {"res": 0, "device_id": 1, "start_addr": 2, "output_value": 255, "function_code": 5}
+        #     ],
+        #     "photosense_1": [
+        #         {"res": 65280, "device_id": 1, "start_addr": 2, "output_value": 0, "function_code": 5}
+        #     ]
+        # }
+        # """
+
+
+    def command_polling(self, data, resend_times=None):
+        '''判断当前模式需要发送的指令'''
+        # data = {'control_mode': 1, 'status': 1, 'definite_time': [["10:00:00,11:00:00"], ["14:00:00,18:00:00"]]}
+        control_mode = data["control_mode"]     # 0:光敏控制,1:手动控制,2:定时控制
+
+        if control_mode == 2:
+            '''定时模式'''
+            light_status = 0
+            now_time = datetime.datetime.now().strftime("%H:%M:%S")
+            definite_time = json.loads(data["definite_time"])
+            # 依次判断每个时间段
+            for each_time in definite_time:
+                each_time = each_time[0].split(",")
+                light_open_time = each_time[0]
+                light_close_time = each_time[1]
+                if light_open_time < light_close_time:
+                    if light_open_time <= now_time <= light_close_time:
+                        light_status = 1
+                else:
+                    if now_time >= light_open_time or now_time <= light_close_time:
+                        light_status = 1
+            light_command = self._command[f"light_{light_status}"]
+            command_res = True
+            for each_command in light_command:
+                res = self.exec_command(each_command)
+            print("------", self._ip, light_command, "return=",res)
+
+
+
+    # 原版:三种模式逻辑正常判断
+    """
+    def command_polling(self, data, resend_times=None):
+        '''判断当前模式需要发送的指令'''
+        # data = {'control_mode': 1, 'status': 1, 'definite_time': [["10:00:00,11:00:00"], ["14:00:00,18:00:00"]]}
+        control_mode = data["control_mode"]     # 0:光敏控制,1:手动控制,2:定时控制
+        photosense_status = 0                   # 光敏模式的状态,默认为关闭
+        light_command = None
+
+        if control_mode == 0:
+            '''光敏模式'''
+            photosense_status = 1
+        else:
+            light_status = 0        # 手动/定时模式时,默认聚鱼灯是关闭状态
+            if control_mode == 1:
+                '''手动模式'''
+                light_status = data["status"]
+            elif control_mode == 2:
+                '''定时模式'''
+                now_time = datetime.datetime.now().strftime("%H:%M:%S")
+                definite_time = json.loads(data["definite_time"])
+                # 依次判断每个时间段
+                for each_time in definite_time:
+                    each_time = each_time[0].split(",")
+                    light_open_time = each_time[0]
+                    light_close_time = each_time[1]
+                    if light_open_time < light_close_time:
+                        if light_open_time <= now_time <= light_close_time:
+                            light_status = 1
+                    else:
+                        if now_time >= light_open_time or now_time <= light_close_time:
+                            light_status = 1
+            light_command = self._command[f"light_{light_status}"]
+
+        # 开启/关闭光敏模式的指令
+        command = self._command[f"photosense_{photosense_status}"]
+        self.exec_command(command)
+        # 非光敏模式下,控制聚鱼灯开关
+        if light_command is not None:
+            self.exec_command(light_command)
+
+    # 特殊版:应对经海四号的光敏模式闪烁问题   就固定早7点关闭,晚6点开启
+    def command_polling(self, data, resend_times=None):
+        '''判断当前模式需要发送的指令'''
+        # data = {'control_mode': 1, 'status': 1, 'definite_time': [["10:00:00,11:00:00"], ["14:00:00,18:00:00"]]}
+        control_mode = data["control_mode"]     # 0:光敏控制,1:手动控制,2:定时控制
+        photosense_status = 0                   # 光敏模式的状态,默认为关闭
+        light_command = None
+
+        if control_mode == 0:
+            '''光敏模式'''
+            # photosense_status = 1
+            photosense_status = 0
+            now = datetime.datetime.now().strftime("%H")
+            if 7 <= int(now) < 18:
+                # 关灯
+                light_command = self._command["light_0"]
+            else:
+                # 开灯
+                light_command = self._command["light_1"]
+        else:
+            light_status = 0        # 手动/定时模式时,默认聚鱼灯是关闭状态
+            if control_mode == 1:
+                '''手动模式'''
+                light_status = data["status"]
+            elif control_mode == 2:
+                '''定时模式'''
+                now_time = datetime.datetime.now().strftime("%H:%M:%S")
+                definite_time = json.loads(data["definite_time"])
+                # 依次判断每个时间段
+                for each_time in definite_time:
+                    each_time = each_time[0].split(",")
+                    light_open_time = each_time[0]
+                    light_close_time = each_time[1]
+                    if light_open_time < light_close_time:
+                        if light_open_time <= now_time <= light_close_time:
+                            light_status = 1
+                    else:
+                        if now_time >= light_open_time or now_time <= light_close_time:
+                            light_status = 1
+            light_command = self._command[f"light_{light_status}"]
+            # print("-------------------------------------------", self._ip, light_status, light_command)
+        # 开启/关闭光敏模式的指令
+        # command = self._command[f"photosense_{photosense_status}"]
+        # self.exec_command(command)
+        # 非光敏模式下,控制聚鱼灯开关
+        if light_command is not None:
+            self.exec_command(light_command)
+
+    """
+
+
+"""
+光敏模式(开启) 发送:01 05 00 02 FF 00 2D FA   接收:01 05 00 02 FF 00 2D FA
+光敏模式(关闭) 发送:01 05 00 02 00 00 6C 0A   接收:01 05 00 02 00 00 6C 0A
+聚鱼灯开启:01 0F 00 00 00 04 01 01 01 00 00 5E 50
+聚鱼灯关闭:01 0F 00 00 00 04 00 00 00 00 00 33 AC
+
+01 ———— 设备地址
+05 ———— 写单个线圈寄存器
+00 02 ———— 起始寄存器地址
+FF 00 ———— 寄存器的值
+2D FA ———— CRC校验
+
+01          ———— 设备地址
+0F          ———— 功能码
+00 00       ———— 起始地址
+00 04       ———— 写入线圈个数
+01          ———— 写入字节数
+01 01 00 00 ———— 写入值
+5E 50       ———— CRC校验
+
+开启光敏模式 photosense_1= {"device_id":1, "function_code":5, "start_addr":2, "output_value":0}
+关闭光敏模式 photosense_0={"device_id":1, "function_code":5, "start_addr":2, "output_value":65280}
+开启聚鱼灯 light_1={"device_id":1, "function_code":15, "start_addr":0, "output_value":[1, 1, 0 ,0]}
+关闭聚鱼灯 light_0={"device_id":1, "function_code":15, "start_addr":0, "output_value":[0, 0, 0 ,0]}
+"""
+
+"""
+light_0:关灯
+light_1:开灯
+{
+    "light_0": [
+        {"res": 0, "device_id": 1, "start_addr": 0, "output_value": 0, "function_code": 5}, 
+        {"res": 0, "device_id": 1, "start_addr": 1, "output_value": 0, "function_code": 5}
+    ], 
+    "light_1": [
+        {"res": 65280, "device_id": 1, "start_addr": 0, "output_value": 65280, "function_code": 5}, 
+        {"res": 65280, "device_id": 1, "start_addr": 1, "output_value": 65280, "function_code": 5}
+    ]
+}
+开启光敏模式 photosense_1= {"device_id":1, "function_code":5, "start_addr":2, "output_value":0}
+关闭光敏模式 photosense_0={"device_id":1, "function_code":5, "start_addr":2, "output_value":65280}
+"""

+ 83 - 0
005_H570/jikong_script/connectors/http_connector.py

@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 11:37
+@desc: http连接器
+"""
+
+
+import json
+import queue
+import time
+import traceback
+import threading
+import requests
+from connector import Connector
+from event_storage import EventStorage
+from log import OutPutLog
+class HttpConnector(Connector, threading.Thread):
+    __master = 0
+    _disConnectTime = 0
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self.__master = None
+        self.__stopped = False
+        self.__connected = False
+        self.__save_frequency = config['save_frequency']  # 数据存储时间间隔
+        self.setDaemon(True)
+        self.setName(name)
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__command_queue = queue.Queue(50)
+        self.__last_save_time = 0
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self.__command = self.__storager.get_command_info(name)
+
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+    def run(self):
+        self.__connected = True
+        command_list = json.loads(self.__command[0]['command'])
+        while True:
+            time.sleep(1)
+            data = []
+            for i in range(len(command_list)):
+                url = command_list['url']
+                postdata = command_list['data']
+                try:
+                    result = requests.post(url, data = json.dumps(postdata),timeout=0.1)
+                    data = json.loads(result.text)
+                except Exception as e:
+                    print('shucai http connect error:{}'.format(str(e)))
+                    time.sleep(5)
+            self.command_polling(data, resend_times=5)
+            
+    def __connect(self):
+        pass
+
+    def __reconnect(self):
+        pass
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self.__connected
+
+    def send_command(self, content):
+        pass
+
+    def command_polling(self, result, resend_times=None):
+        format_data = self.__converter.convert(self.__data_point_config, result)
+        if format_data:
+            if format_data != "error" and format_data != 'pass':
+                # 往redis存储数据
+                self.__storager.real_time_data_storage(format_data)

+ 170 - 0
005_H570/jikong_script/connectors/melsec_plc_a1e_connector.py

@@ -0,0 +1,170 @@
+import json
+import queue
+import time
+import threading
+import datetime
+import ast
+from connector import Connector
+from event_storage import EventStorage
+from libs.hls1_1_0 import MelsecA1ENet
+#from libs.hls import MelsecA1ENet
+from log import OutPutLog
+
+class MelsecPlcA1EConnector(Connector, threading.Thread):
+    __master = 0
+    _disConnectTime = 0
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self.__master = None
+        self.__stopped = False
+        self.__connected = False
+        self._ip = config['ip']  # ip
+        self._port = config['port']  # 端口
+        self.__save_frequency = config['save_frequency']  # 数据存储时间间隔
+        self.setDaemon(True)
+        self.setName(name)
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__command_queue = queue.Queue(1)
+        self.__last_save_time = 0
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self.__command = self.__storager.get_command_info(name)
+
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+    def run(self):
+        self.__connect()
+        self.__connected = True
+        command_list = json.loads(self.__command[0]['command'])
+        while True:
+            time.sleep(0.1)
+            try:
+                self.command_polling(command_list, resend_times=5)
+            except Exception as e:
+                print(e)
+            # print('runing...')
+            if self.__stopped:
+                break
+
+    def __connect(self):
+        try:
+            self.__master = MelsecA1ENet(self._ip, self._port)
+            if self.__master.ConnectServer().IsSuccess == False:
+                self.__connected = False
+                print("MelsecPlcA1EConnector connect falied:", self._ip, self._port)
+            else:
+                self.__connected = True
+                print("MelsecPlcA1EConnector connect success:", self._ip, self._port)
+        except Exception as e:
+            self._log.error(e)
+
+    def __reconnect(self):
+        pass
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self.__connected
+
+    def send_command(self, data):
+        try:
+            for command in data:
+                try:
+                    self.__command_queue.put_nowait(command)
+                    return "success"
+                except queue.Full:
+                    return "queue.Full"           
+        except Exception as e:
+            print(e)
+            return "send_command error"+str(e)
+
+    def command_polling(self, command_list, resend_times=None):
+        #msg = str(time.strftime("%Y-%m-%d %H:%M:%S")
+        for i in range(len(command_list)):
+            command_item = command_list[i]
+            # print("self.__command_queue.qsize()123221 = ", self.__command_queue.qsize())
+            if not self.__command_queue.empty():
+                # print("self.__command_queue.qsize() before write = ", self.__command_queue.qsize())
+                write_command = self.__command_queue.get()  # 写命令来自数组
+                # print("self.__command_queue.qsize() after write = ", self.__command_queue.qsize())                
+                try:
+                    self.writeData(write_command['addr_data'], write_command['data_type'], write_command['data'])
+                    print("send:"+ str(time.time()))
+                    #self._log.info('success'+str(res))
+                except Exception as e:
+                    print("A1EConverter,write[ERROR]:" + str(e))
+                    self._log.error("A1EConverter,write[ERROR]:" + str(e))
+                '''
+                if not res:
+                    # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                    sent_times = 1
+                    while sent_times < resend_times:
+                        res = self.exec_command(write_command)
+                        sent_times += 1
+                        if res:
+                            break
+                '''
+            else:
+                # 格式化数据
+                result = {}
+                start_addr = command_item['start_addr']
+                length = command_item['length']
+                db_number = start_addr[:1]              
+                result[db_number] = self.read_batch_data(start_addr, length)
+                format_data = self.__converter.convert(self.__data_point_config, result, self.__master)
+                if format_data:
+                    if format_data != "error" and format_data != 'pass':
+                         # 往redis存储数据
+                        self.__storager.real_time_data_storage(format_data)
+                        self._log.info('success -- 实时数据存入redis!')
+    '''
+    def read_batch_data(self, addr, length):
+        try:
+            self.__master.ConnectServer().IsSuccess)
+            result = self.__master.Read(addr, length)
+            if result.IsSuccess:
+                print("success____________________________________________")
+            else:
+                print("falied_______________________________________  " + result.Message) 
+            #datas = self.__master.Read(addr, length).Content
+            #print(datas)
+            return None
+            #return datas
+        except Exception as e:
+            print("A1EConverter,read[ERROR]:" + str(e))
+            return None
+    '''
+            
+    def read_batch_data(self, addr, length):
+        try:
+            result = self.__master.Read(addr, length)
+            if result.IsSuccess:
+                datas = result.Content
+                return datas
+            else:
+                if self.__master.ConnectServer().IsSuccess == False:
+                    self.__connected = False
+                else:
+                    self.__connected = True
+                return datas
+        except Exception as e:
+            print("A1EConverter,read[ERROR]:" + str(e))
+            return None            
+
+    def writeData(self, address, data_type, data):
+        data_addr = self.address_transform(address)
+        if data_type == "BOOL":
+            data = int(data)
+            self.__master.WriteBool(data_addr, data)
+
+    def address_transform(self, addr):
+        return addr

+ 175 - 0
005_H570/jikong_script/connectors/modbus_moxae1210_connector.py

@@ -0,0 +1,175 @@
+import json
+import queue
+import time
+
+import threading
+# from modbus_tk import modbus_tcp
+from connector import Connector
+from event_storage import EventStorage
+import modbus_rtu_over_tcp_special
+import modbus_tk.modbus_tcp as modbus_tcp
+from log import OutPutLog
+
+class ModbusMoxae1210Connector(Connector, threading.Thread):
+    __master = 0
+    _disConnectTime = 0
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self.__master = None
+        self.__stopped = False
+        self.__connected = False
+        self._ip = config['ip']  # ip
+        self._port = config['port']  # 端口
+        self._deviceID = config['deviceID']  # 设备地址
+        self.__save_frequency = config['save_frequency']  # 数据存储时间间隔
+        self.setDaemon(True)
+        self.setName(name)
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__command_queue = queue.Queue(50)
+        self.__last_save_time = 0
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self.__command = self.__storager.get_command_info(name)
+
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+    def run(self):
+        self.__connect()
+        self.__connected = True
+        command_list = self.__command
+        while True:
+            time.sleep(1)
+            for i in range(len(command_list)):
+                command_item = json.loads(command_list[i]['command'])   # {'length': 20, 'start_addr': 4096, 'output_value': [], 'function_code': 3}
+                result = self.exec_command(command=command_item)
+                if not result:
+                    # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                    sent_times = 1
+                    while sent_times < 5:
+                        result = self.exec_command(command=command_item)
+                        sent_times += 1
+                        if result:
+                            break
+                else:
+                    self.command_polling(result, resend_times=5)
+            if self.__stopped:
+                break
+
+    def __connect(self):
+        try:
+            self.__master = modbus_tcp.TcpMaster(host=self._ip, port=self._port)
+            # self.__master = modbus_rtu_over_tcp_special.RtuOverTcpMasterSpecial(host=self._ip, port=self._port)
+        except Exception as e:
+            self._log.error(e)
+
+    def __reconnect(self):
+        while True:
+            try:
+                self.__master = modbus_tcp.TcpMaster(host=self._ip)
+                # self.__master = modbus_rtu_over_tcp_special.RtuOverTcpMasterSpecial(host=self._ip, port=self._port)
+                print('client start connect to host/port:{}'.format(self._port))
+                break
+            except ConnectionRefusedError:
+                print('modbus server refused or not started, reconnect to server in 5s .... host/port:{}'.format(
+                    self._port))
+                time.sleep(5)
+            except Exception as e:
+                print('do connect error:{}'.format(str(e)))
+                time.sleep(5)
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self.__connected
+
+    def send_command(self, content):
+        pass
+
+    def exec_command(self, command):
+        """
+        0x01: 读线圈寄存器
+        0x02: 读离散输入寄存器
+        0x03: 读保持寄存器
+        0x04: 读输入寄存器
+        0x05: 写单个线圈寄存器
+        0x06: 写单个保持寄存器
+        0x0f: 写多个线圈寄存器
+        0x10: 写多个保持寄存器
+        #supported modbus functions
+        READ_COILS = 1
+        READ_DISCRETE_INPUTS = 2
+        READ_HOLDING_REGISTERS = 3
+        READ_INPUT_REGISTERS = 4
+        WRITE_SINGLE_COIL = 5
+        WRITE_SINGLE_REGISTER = 6
+        READ_EXCEPTION_STATUS = 7
+        DIAGNOSTIC = 8
+        REPORT_SLAVE_ID = 17
+        WRITE_MULTIPLE_COILS = 15
+        WRITE_MULTIPLE_REGISTERS = 16
+        READ_WRITE_MULTIPLE_REGISTERS = 23
+        DEVICE_INFO = 43
+        """
+        time.sleep(0.1)
+        datadict = {}
+        msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        function_code = int(command['function_code'])
+        start_addr = int(command['start_addr'])
+        length = int(command['length'])
+        output_value = command['output_value']
+        if function_code in (1, 2, 3, 4):
+            # 读寄存器
+            try:
+                self.__master.set_timeout(0.5)
+                self.__master.set_verbose(True)
+                receive_data = self.__master.execute(self._deviceID, function_code, start_addr, length)
+                for i in range(len(receive_data)):
+                    addr = start_addr+i
+                    datadict[addr] = receive_data[i]
+                result = [self._deviceID, datadict]
+                return result
+            except Exception as e:
+                self._log.error(e)
+        elif function_code in (5, 6, 15, 16):
+            # 写寄存器
+            try:
+                self.__master.set_timeout(1.0)
+                self.__master.set_verbose(True)
+                data = self.__master.execute(self._deviceID, function_code, start_addr, output_value=output_value)
+                return data
+            except Exception as e:
+                self._log.error(e)
+        else:
+            self._log.debug(f'Unsupported function code.')
+
+    def command_polling(self, result, resend_times=None):
+        msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        if not self.__command_queue.empty():
+            write_command = self.__command_queue.get()  # 写命令来自数组
+            res = self.exec_command(write_command)
+            if not res:
+                # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                sent_times = 1
+                while sent_times < resend_times:
+                    res = self.exec_command(write_command)
+                    sent_times += 1
+                    if res:
+                        break
+
+        else:
+            # 格式化数据
+            format_data = self.__converter.convert(self.__data_point_config, result)
+            if format_data:
+                if format_data != "error" and format_data != 'pass':
+                     # 往redis存储数据
+                    self.__storager.real_time_data_storage(format_data)
+                    self._log.info('success -- 实时数据存入redis!')

+ 194 - 0
005_H570/jikong_script/connectors/modbus_rtu_over_tcp_connector.py

@@ -0,0 +1,194 @@
+import json
+import queue
+import time
+import traceback
+
+import threading
+# from modbus_tk import modbus_tcp
+from connector import Connector
+from event_storage import EventStorage
+import modbus_rtu_over_tcp_special
+import modbus_tk.modbus_tcp as modbus_tcp
+from log import OutPutLog
+
+class ModbusRtuOverTcpConnector(Connector, threading.Thread):
+    __master = 0
+    _disConnectTime = 0
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self.__master = None
+        self.__stopped = False
+        self.__connected = False
+        self._ip = config['ip']  # ip
+        self._port = config['port']  # 端口
+        self._deviceID = config['deviceID']  # 设备地址
+        self.__save_frequency = config['save_frequency']  # 数据存储时间间隔
+        self.setDaemon(True)
+        self.setName(name)
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__command_queue = queue.Queue(500)
+        self.__last_save_time = 0
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self.__command = self.__storager.get_command_info(name)
+
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+    def run(self):
+        self.__connect()
+        self.__connected = True
+        command_list = json.loads(self.__command[0]['command'])
+        while True:
+            time.sleep(1)
+            self.command_polling(command_list, resend_times=5)
+            if self.__stopped:
+                break
+
+    def __connect(self):
+        try:
+            self.__master = modbus_rtu_over_tcp_special.RtuOverTcpMasterSpecial(host=self._ip, port=self._port)
+            print('modbus connected!')
+        except Exception as e:
+            self._log.error(e)
+
+    def __reconnect(self):
+        while True:
+            try:
+                # self.__master = modbus_tcp.TcpMaster(host=self._ip)
+                self.__master = modbus_rtu_over_tcp_special.RtuOverTcpMasterSpecial(host=self._ip, port=self._port)
+                print('client start connect to host/port:{}'.format(self._port))
+                break
+            except ConnectionRefusedError:
+                print('modbus server refused or not started, reconnect to server in 5s .... host/port:{}'.format(
+                    self._port))
+                time.sleep(5)
+            except Exception as e:
+                print('do connect error:{}'.format(str(e)))
+                time.sleep(5)
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self.__connected
+
+    def send_command(self, data):
+        try:
+            for command in data:
+                self.__command_queue.put(command)
+            return "success"
+        except Exception as e:
+            print(e)
+            return "send_command error"+str(e)
+
+    def exec_command(self, command):
+        """
+        0x01: 读线圈寄存器
+        0x02: 读离散输入寄存器
+        0x03: 读保持寄存器
+        0x04: 读输入寄存器
+        0x05: 写单个线圈寄存器
+        0x06: 写单个保持寄存器
+        0x0f: 写多个线圈寄存器
+        0x10: 写多个保持寄存器
+        #supported modbus functions
+        READ_COILS = 1
+        READ_DISCRETE_INPUTS = 2
+        READ_HOLDING_REGISTERS = 3
+        READ_INPUT_REGISTERS = 4
+        WRITE_SINGLE_COIL = 5
+        WRITE_SINGLE_REGISTER = 6
+        READ_EXCEPTION_STATUS = 7
+        DIAGNOSTIC = 8
+        REPORT_SLAVE_ID = 17
+        WRITE_MULTIPLE_COILS = 15
+        WRITE_MULTIPLE_REGISTERS = 16
+        READ_WRITE_MULTIPLE_REGISTERS = 23
+        DEVICE_INFO = 43
+        """
+        time.sleep(0.1)
+        datadict = {}
+        msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        function_code = int(command['function_code'])
+        start_addr = int(command['start_addr'])
+        start_addr_command = start_addr
+        length = int(command['length'])
+        output_value = command['output_value']
+        if function_code in (1, 2, 3, 4):
+            # 读寄存器
+            try:
+                self.__master.set_timeout(0.5)
+                self.__master.set_verbose(True)
+                res = ()
+                num = 40
+                if length > num:
+                    count = length/num
+                    while count > 0:
+                        if count < 1:
+                            le = length % num
+                        else:
+                            le = num
+                        receive_data = self.__master.execute(self._deviceID, function_code, start_addr_command, le)     # 203 3 4096 20
+                        res = res+receive_data
+                        start_addr_command = start_addr_command+num
+                        count = count-1
+                else:
+                    le = length
+                    res = self.__master.execute(self._deviceID, function_code, start_addr, le)  # 203 3 4096 20
+                for i in range(len(res)):
+                    addr = start_addr+i
+                    datadict[addr] = res[i]
+                return datadict
+            except Exception as e:
+                self._log.error(e)
+        elif function_code in (5, 6, 15, 16):
+            # 写寄存器
+            try:
+                self.__master.set_timeout(1.0)
+                self.__master.set_verbose(True)
+                data = self.__master.execute(self._deviceID, function_code, start_addr, output_value=output_value)
+                print(data)
+                return data
+            except Exception as e:
+                self._log.error(e)
+        else:
+            self._log.debug(f'Unsupported function code.')
+
+    def command_polling(self, command_list, resend_times=None):
+        #msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        for i in range(len(command_list)):
+            command_item = command_list[i]
+            if not self.__command_queue.empty():
+                write_command = self.__command_queue.get()  # 写命令来自数组
+                try:
+                    res = self.exec_command(command=write_command)
+                    print(res)
+                except Exception as e:
+                    print("mofbus_rtu,write[ERROR]:" + str(e))
+                '''
+                if not res:
+                    # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                    sent_times = 1
+                    while sent_times < resend_times:
+                        res = self.exec_command(write_command)
+                        sent_times += 1
+                        if res:
+                            break
+                '''
+            else:
+                # 格式化数据
+                result = self.exec_command(command=command_item)
+                format_data = self.__converter.convert(self.__data_point_config, result)
+                #print(format_data)
+                if format_data:
+                    if format_data != "error" and format_data != 'pass':
+                        # 往redis存储数据
+                        self.__storager.real_time_data_storage(format_data)

+ 226 - 0
005_H570/jikong_script/connectors/modbus_rtu_over_tcp_normal.py

@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2021/12/8 14:57
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 蜂鸣器的连接器,控制蜂鸣器的开关
+"""
+
+import json
+import threading
+import queue
+from connector import Connector
+from event_storage import EventStorage
+from log import OutPutLog
+import time
+import datetime
+from modbus_tk import modbus_rtu_over_tcp
+
+
+class ModbusRtuOverTcpNormalConnector(Connector, threading.Thread):
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self._master = None
+        self.__stopped = False
+        self._connected = False
+        self._ip = config['ip']  # ip
+        self._port = config['port']  # 端口
+        self._save_frequency = config['save_frequency']  # 数据存储时间间隔
+        self._set_timeout = int(config['set_timeout'])	#读取超时时间设置
+        self.setDaemon(True)
+        self.setName(name)
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__command_queue = queue.Queue(500)
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self._name = name
+        self.run_time = 0
+        self._command = self.__storager.get_command_info(name)
+
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+
+    def run(self):
+        self._connect()
+        self._connected = True
+        if isinstance(self._command, list):
+            command_list = json.loads(self._command[0]['command'])
+            # print("----------------------", self._ip, self._port, type(command_list), command_list)
+            while True:
+                time.sleep(1)
+                self.command_polling(command_list, resend_times=5)
+                if self.__stopped:
+                    break
+
+    def _connect(self):
+        try:
+            self._master = modbus_rtu_over_tcp.RtuOverTcpMaster(host=self._ip, port=self._port)
+            print(f"{self._ip}:{self._port} connect success!")
+        except Exception as e:
+            print(f"{self._ip}:{self._port} connect failed!")
+            self._log.error(f"{self._ip}:{self._port} connect failed! error={e}")
+            self._connected = False
+            self._reconnect()
+
+
+    def _reconnect(self):
+        while True:
+            try:
+                self._master = modbus_rtu_over_tcp.RtuOverTcpMaster(host=self._ip, port=self._port)
+                print('client start connect to host/port:{}'.format(self._port))
+                break
+            except ConnectionRefusedError:
+                print('modbus server refused or not started, reconnect to server in 2s .... host/port:{}'.format(self._port))
+                time.sleep(2)
+            except Exception as e:
+                print('do connect error:{}'.format(str(e)))
+                time.sleep(2)
+
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self._connected
+
+    def send_command(self, command):
+        # command = {'device_id': 1, 'start_addr': 0, 'output_value': [0, 0, 0, 0], 'function_code': 15}
+        # print(f"[send_command] {command}")
+        try:
+            if isinstance(command, dict):
+                result = self.exec_command(command)
+            elif isinstance(command, list):
+                for each in command:
+                    result = self.exec_command(each)
+        except Exception as e:
+            print(f"[ModbusTcpConnector][send_command] error: {e}")
+            result = False
+
+        # print(f"[send_command][result] {result}")
+        return result
+
+
+
+    def exec_command(self, command):
+        """
+        0x01: 读线圈寄存器
+        0x02: 读离散输入寄存器
+        0x03: 读保持寄存器
+        0x04: 读输入寄存器
+        0x05: 写单个线圈寄存器
+        0x06: 写单个保持寄存器
+        0x0f: 写多个线圈寄存器
+        0x10: 写多个保持寄存器
+        #supported modbus functions
+        READ_COILS = 1
+        READ_DISCRETE_INPUTS = 2
+        READ_HOLDING_REGISTERS = 3
+        READ_INPUT_REGISTERS = 4
+        WRITE_SINGLE_COIL = 5
+        WRITE_SINGLE_REGISTER = 6
+        READ_EXCEPTION_STATUS = 7
+        DIAGNOSTIC = 8
+        REPORT_SLAVE_ID = 17
+        WRITE_MULTIPLE_COILS = 15
+        WRITE_MULTIPLE_REGISTERS = 16
+        READ_WRITE_MULTIPLE_REGISTERS = 23
+        DEVICE_INFO = 43
+        """
+        time.sleep(0.1)
+        if isinstance(command, str):
+            command = json.loads(command)
+        device_id = int(command['device_id'])
+        function_code = int(command['function_code'])
+        start_addr = int(command['start_addr'])
+
+        if function_code in (1, 2, 3, 4):
+            # 读寄存器
+            length = int(command['length'])
+            try:
+                self._master.set_timeout(self._set_timeout)
+                self._master.set_verbose(True)
+                # print(self._ip, self._port, device_id, function_code, start_addr, length)
+                receive_data = self._master.execute(device_id, function_code, start_addr, length)
+                datadict = {}
+                for i in range(len(receive_data)):
+                    addr = start_addr+i
+                    datadict[addr] = receive_data[i]
+                result = [device_id, datadict]
+
+                # print(self._ip, self._port,device_id, result)
+
+            except Exception as e:
+                print(self._ip, self._port, device_id, start_addr, length, "error = ", e)
+                self._log.error(e)
+                result = False
+            return result
+
+        elif function_code in (5, 6, 15, 16):
+            # 写寄存器
+            output_value = command['output_value']
+            try:
+                self._master.set_timeout(1.0)
+                self._master.set_verbose(True)
+                # print("-----------------", self._ip, self._port, command)
+                data = self._master.execute(device_id, function_code, start_addr, output_value=output_value)
+                print("************************-----------------", self._ip, self._port, device_id,output_value, data)
+                # print("data = ", data)
+                # data = (0, 65280) or (0, 0)
+                result = True
+                if function_code == 5 and "res" in command.keys():
+                    res = command["res"]
+                    if start_addr == data[0] and res == data[1]:
+                        pass
+                    else:
+                        result = False
+                return result
+            except Exception as e:
+                self._log.error(e)
+                print(f"[exec_command] e = {e}")
+                return False
+        else:
+            self._log.debug(f'Unsupported function code.')
+
+
+
+    def command_polling(self, command_list, resend_times=None):
+        #msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        for i in range(len(command_list)):
+            command_item = command_list[i]
+            if not self.__command_queue.empty():
+                write_command = self.__command_queue.get()  # 写命令来自数组
+                try:
+                    res = self.exec_command(command=write_command)
+                    print(res)
+                except Exception as e:
+                    print("mofbus_rtu,write[ERROR]:" + str(e))
+                '''
+                if not res:
+                    # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                    sent_times = 1
+                    while sent_times < resend_times:
+                        res = self.exec_command(write_command)
+                        sent_times += 1
+                        if res:
+                            break
+                '''
+
+            else:
+                # 格式化数据
+                result = self.exec_command(command=command_item)
+                if result:
+                    format_data = self.__converter.convert(self.__data_point_config, result)
+                    #print(format_data)
+                    if format_data:
+                        if format_data != "error" and format_data != 'pass':
+                            # 往redis存储数据
+                            self.__storager.real_time_data_storage(format_data)

+ 210 - 0
005_H570/jikong_script/connectors/modbus_tcp_connector.py

@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/07/03 08:50
+@Author: lxc
+@LastEditTime:
+@Desctiption:
+"""
+
+import json
+import queue
+import time
+import traceback
+
+import threading
+# from modbus_tk import modbus_tcp
+from connector import Connector
+from event_storage import EventStorage
+import modbus_tk.modbus_tcp as modbus_tcp
+from log import OutPutLog
+
+class ModbusTcpConnector(Connector, threading.Thread):
+    __master = 0
+    _disConnectTime = 0
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self.__master = None
+        self.__stopped = False
+        self.__connected = False
+        self._ip = config['ip']  # ip
+        self._port = config['port']  # 端口
+        self.__save_frequency = config['save_frequency']  # 数据存储时间间隔
+        self.setDaemon(True)
+        self.setName(name)
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__command_queue = queue.Queue(500)
+        self.__last_save_time = 0
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self.__command = self.__storager.get_command_info(name)
+
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+    def run(self):
+        self.__connect()
+        self.__connected = True
+        command_list = json.loads(self.__command[0]['command'])
+        while True:
+            time.sleep(1)
+            self.command_polling(command_list, resend_times=5)
+            if self.__stopped:
+                break
+
+    def __connect(self):
+        try:
+            self.__master = modbus_tcp.TcpMaster(host=self._ip, port=self._port)
+            print(self._ip, self._port, 'connect success!')
+
+        except Exception as e:
+            self._log.error(e)
+            print(self._ip, self._port, 'connect failed!', e)
+
+
+    def __reconnect(self):
+        while True:
+            try:
+                # self.__master = modbus_tcp.TcpMaster(host=self._ip)
+                self.__master = modbus_tcp.TcpMaster(host=self._ip, port=self._port)
+                print('client start connect to host/port:{}'.format(self._port))
+                break
+            except ConnectionRefusedError:
+                print(self._ip, self._port, 'reconnect success!')
+                time.sleep(5)
+            except Exception as e:
+                print(self._ip, self._port, 'reconnect failed!', e)
+                time.sleep(5)
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self.__connected
+
+    def send_command(self, data):
+        try:
+            for command in data:
+                self.__command_queue.put(command)
+            return "success"
+        except Exception as e:
+            print(e)
+            return "send_command error"+str(e)
+
+    def exec_command(self, command):
+        """
+        0x01: 读线圈寄存器
+        0x02: 读离散输入寄存器
+        0x03: 读保持寄存器
+        0x04: 读输入寄存器
+        0x05: 写单个线圈寄存器
+        0x06: 写单个保持寄存器
+        0x0f: 写多个线圈寄存器
+        0x10: 写多个保持寄存器
+        #supported modbus functions
+        READ_COILS = 1
+        READ_DISCRETE_INPUTS = 2
+        READ_HOLDING_REGISTERS = 3
+        READ_INPUT_REGISTERS = 4
+        WRITE_SINGLE_COIL = 5
+        WRITE_SINGLE_REGISTER = 6
+        READ_EXCEPTION_STATUS = 7
+        DIAGNOSTIC = 8
+        REPORT_SLAVE_ID = 17
+        WRITE_MULTIPLE_COILS = 15
+        WRITE_MULTIPLE_REGISTERS = 16
+        READ_WRITE_MULTIPLE_REGISTERS = 23
+        DEVICE_INFO = 43
+        """
+        time.sleep(0.1)
+        datadict = {}
+        msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        device_id = int(command['device_id'])
+        function_code = int(command['function_code'])
+        start_addr = int(command['start_addr'])
+        start_addr_command = start_addr
+
+
+        if function_code in (1, 2, 3, 4):
+            # 读寄存器
+            try:
+                length = int(command['length'])
+                self.__master.set_timeout(0.5)
+                self.__master.set_verbose(True)
+                res = ()
+                num = 40
+                if length > num:
+                    count = length/num
+                    while count > 0:
+                        if count < 1:
+                            le = length % num
+                        else:
+                            le = num
+                        receive_data = self.__master.execute(device_id, function_code, start_addr_command, le)     # 203 3 4096 20
+                        res = res+receive_data
+                        start_addr_command = start_addr_command+num
+                        count = count-1
+                else:
+                    le = length
+                    # print("-----------------------",device_id, function_code, start_addr, le)
+                    res = self.__master.execute(device_id, function_code, start_addr, le)  # 203 3 4096 20
+                    # print("--------------------", res)
+                for i in range(len(res)):
+                    addr = start_addr+i
+                    datadict[addr] = res[i]
+                result = [device_id, datadict]
+                # print("--------------------",self._ip, self._port, result)
+                return result
+            except Exception as e:
+                self._log.error(e)
+        elif function_code in (5, 6, 15, 16):
+            # 写寄存器
+            try:
+                output_value = command['output_value']
+                self.__master.set_timeout(1.0)
+                self.__master.set_verbose(True)
+                data = self.__master.execute(device_id, function_code, start_addr, output_value=output_value)
+                print(data)
+                return data
+            except Exception as e:
+                self._log.error(e)
+        else:
+            self._log.debug(f'Unsupported function code.')
+
+    def command_polling(self, command_list, resend_times=None):
+        #msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        for i in range(len(command_list)):
+            command_item = command_list[i]
+            if not self.__command_queue.empty():
+                write_command = self.__command_queue.get()  # 写命令来自数组
+                try:
+                    res = self.exec_command(command=write_command)
+                    print(res)
+                except Exception as e:
+                    print("mofbus_rtu,write[ERROR]:" + str(e))
+                '''
+                if not res:
+                    # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                    sent_times = 1
+                    while sent_times < resend_times:
+                        res = self.exec_command(write_command)
+                        sent_times += 1
+                        if res:
+                            break
+                '''
+            else:
+                # 格式化数据
+                result = self.exec_command(command=command_item)
+                format_data = self.__converter.convert(self.__data_point_config, result)
+                #print(format_data)
+                if format_data:
+                    if format_data != "error" and format_data != 'pass':
+                        # 往redis存储数据
+                        self.__storager.real_time_data_storage(format_data)

+ 192 - 0
005_H570/jikong_script/connectors/siemens_plc_s7_connector.py

@@ -0,0 +1,192 @@
+import json
+import queue
+import time
+import threading
+import datetime
+import ast
+from connector import Connector
+from event_storage import EventStorage
+from libs.hls import SiemensS7Net
+from libs.hls import SiemensPLCS
+from log import OutPutLog
+
+class SiemensPlcS7Connector(Connector, threading.Thread):
+    __master = 0
+    _disConnectTime = 0
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self.__master = None
+        self.__stopped = False
+        self.__connected = False
+        self._ip = config['ip']  # ip
+        self._port = config['port']  # 端口
+        self.__save_frequency = config['save_frequency']  # 数据存储时间间隔
+        self.setDaemon(True)
+        self.setName(name)
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__command_queue = queue.Queue(500)
+        self.__last_save_time = 0
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self.__command = self.__storager.get_command_info(name)
+
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+    def run(self):
+        self.__connect()
+        command_list = json.loads(self.__command[0]['command'])
+        while True:
+            time.sleep(0.1)
+            self.command_polling(command_list, resend_times=5)
+            if self.__stopped:
+                break
+
+    def __connect(self):
+        try:
+            self.__master = SiemensS7Net(SiemensPLCS.S1200, self._ip, self._port)
+            if self.__master.ConnectServer().IsSuccess == False:
+                self.__connected = False
+                #print("s7 connect falied")
+            else:
+                self.__connected = True
+                #print("s7 connect success")
+        except Exception as e:
+            self._log.error(e)
+
+    def __reconnect(self):
+        pass
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self.__connected
+
+    def send_command(self, data):
+        try:
+            for command in data:
+                self.__command_queue.put(command)
+            return "success"
+        except Exception as e:
+            print(e)
+            return "send_command error"+str(e)
+
+    def command_polling(self, command_list, resend_times=None):
+        #msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        for i in range(len(command_list)):
+            command_item = command_list[i]
+            if not self.__command_queue.empty():
+                write_command = self.__command_queue.get()  # 写命令来自数组
+                try:
+                    self.writeData(write_command['addr_data'],write_command['data_type'] , write_command['data'])
+                    #self._log.info('success'+str(res))
+                except Exception as e:
+                    print("S7Converter,write[ERROR]:" + str(e))
+                    self._log.error("S7Converter,write[ERROR]:" + str(e))
+                '''
+                if not res:
+                    # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                    sent_times = 1
+                    while sent_times < resend_times:
+                        res = self.exec_command(write_command)
+                        sent_times += 1
+                        if res:
+                            break
+                '''
+            else:
+                # 格式化数据
+                result = {}
+                start_addr = command_item['start_addr']
+                length = command_item['length']
+                db_number = "".join(start_addr).split(".")[0]
+                result[db_number] = self.read_batch_data(start_addr, length)
+                # print("-----------------", self._ip, self._port, start_addr, length, result)
+                format_data = self.__converter.convert(self.__data_point_config, result, self.__master)
+                if format_data:
+                    if format_data != "error" and format_data != 'pass':
+                         # 往redis存储数据
+                        self.__storager.real_time_data_storage(format_data)
+                        self._log.info('success -- 实时数据存入redis!')
+
+    def read_batch_data(self, addr, length):
+        try:
+            result = self.__master.Read(addr, length)
+            if result.IsSuccess:
+                datas = result.Content
+                return datas
+            else:
+                if self.__master.ConnectServer().IsSuccess == False:
+                    self.__connected = False
+                    #print("s7 connect falied")
+                else:
+                    self.__connected = True
+                    #print("s7 connect success")
+                return None
+        except Exception as e:
+            print("S7Converter,read[ERROR]:" + str(e))
+            return None
+
+    def writeData(self, address, data_type, data):
+        data_addr = self.address_transform(address)
+        if data_type == "BOOL":
+            data = int(data)
+            self.__master.WriteBool(data_addr, data)
+        elif data_type == "DTL":
+            data_conversion = data.split(" ")
+            data_conversion_date = data_conversion[0].split("-")
+            data_conversion_time = data_conversion[1].split(":")
+            year_h = int(data_conversion_date[0]) >> 8
+            year_l = int(data_conversion_date[0]) - year_h * 256
+            write_month = int(data_conversion_date[1])
+            write_days = int(data_conversion_date[2])
+            write_hours = int(data_conversion_time[0])
+            write_min = int(data_conversion_time[1])
+            write_sec = int(data_conversion_time[2])
+            data_in = bytes([year_h, year_l, write_month, write_days, 0, write_hours, write_min, write_sec, 0, 0, 0, 0])
+            self.__master.Write(data_addr, data_in)
+        elif data_type == "FLOAT32":
+            data = float(data)
+            self.__master.WriteFloat(data_addr, data)
+        elif data_type == "UINT8":
+            data = int(data)
+            self.__master.WriteByte(data_addr, data)
+
+    def readData(self, addr_data, data_type):
+
+        data_addr = self.address_transform(addr_data)
+        if data_type == "BOOL":
+            data_is = self.__master.ReadBool(data_addr).Content  # 读布尔类型
+            return data_is
+        elif data_type == "DTL":
+            data_is = self.__master.Read(data_addr, 12).Content  # 读布尔类型ReadDouble
+            year = int(data_is[0]) * 256 + int(data_is[1])
+            month = int(data_is[2])
+            day = int(data_is[3])
+            hour = int(data_is[5])
+            minute = int(data_is[6])
+            sec = int(data_is[7])
+            times = str(year) + "-" + str(month) + "-" + str(day) + " " + str(hour) + ":" + str(minute) + ":" + str(sec)
+            timeStruct = time.strptime(times, "%Y-%m-%d %H:%M:%S")
+            times = time.strftime("%Y-%m-%d %H:%M:%S", timeStruct)
+            return times
+        elif data_type == "FLOAT":
+            data_is = self.__master.ReadFloat(data_addr).Content
+        elif data_type == "UINT8":
+            data_is = self.__master.ReadByte(data_addr).Content
+        return data_is
+
+    def address_transform(self, addr):
+        real_addr_buffer = "".join(addr).split(".")  # 合并list为字符串 用“.”分割字符串获得数据
+        if real_addr_buffer[1][2] == 'X':
+            data_addr = real_addr_buffer[0] + "." + real_addr_buffer[1][3:] + "." + real_addr_buffer[2]
+        elif real_addr_buffer[1][2] == 'D' or real_addr_buffer[1][2] == 'B':
+            data_addr = real_addr_buffer[0] + "." + real_addr_buffer[1][3:]
+        return data_addr

+ 192 - 0
005_H570/jikong_script/connectors/siemens_plc_s7_s200smart_connector.py

@@ -0,0 +1,192 @@
+import json
+import queue
+import time
+import threading
+import datetime
+import ast
+from connector import Connector
+from event_storage import EventStorage
+from libs.hls import SiemensS7Net
+from libs.hls import SiemensPLCS
+from log import OutPutLog
+
+class SiemensPlcS7S200smartConnector(Connector, threading.Thread):
+    __master = 0
+    _disConnectTime = 0
+
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self.__master = None
+        self.__stopped = False
+        self.__connected = False
+        self._ip = config['ip']  # ip
+        self._port = config['port']  # 端口
+        self.__save_frequency = config['save_frequency']  # 数据存储时间间隔
+        self.setDaemon(True)
+        self.setName(name)
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__command_queue = queue.Queue(500)
+        self.__last_save_time = 0
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self.__command = self.__storager.get_command_info(name)
+
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+    def run(self):
+        self.__connect()
+        command_list = json.loads(self.__command[0]['command'])
+        while True:
+            time.sleep(0.1)
+            self.command_polling(command_list, resend_times=5)
+            if self.__stopped:
+                break
+
+    def __connect(self):
+        try:
+            self.__master = SiemensS7Net(SiemensPLCS.S200Smart, self._ip, self._port)
+            if self.__master.ConnectServer().IsSuccess == False:
+                self.__connected = False
+                print("s7 connect falied", self._ip, self._port)
+            else:
+                self.__connected = True
+                print("s7 connect success", self._ip, self._port)
+        except Exception as e:
+            self._log.error(e)
+
+    def __reconnect(self):
+        pass
+
+    def close(self):
+        pass
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self.__connected
+
+    def send_command(self, data):
+        try:
+            for command in data:
+                self.__command_queue.put(command)
+            return "success"
+        except Exception as e:
+            print(e)
+            return "send_command error"+str(e)
+
+    def command_polling(self, command_list, resend_times=None):
+        #msg = str(time.strftime("%Y-%m-%d %H:%M:%S"))
+        for i in range(len(command_list)):
+            command_item = command_list[i]
+            if not self.__command_queue.empty():
+                write_command = self.__command_queue.get()  # 写命令来自数组
+                try:
+                    self.writeData(write_command['addr_data'],write_command['data_type'] , write_command['data'])
+                    #self._log.info('success'+str(res))
+                except Exception as e:
+                    print("S7Converter,write[ERROR]:" + str(e))
+                    self._log.error("S7Converter,write[ERROR]:" + str(e))
+                '''
+                if not res:
+                    # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                    sent_times = 1
+                    while sent_times < resend_times:
+                        res = self.exec_command(write_command)
+                        sent_times += 1
+                        if res:
+                            break
+                '''
+            else:
+                # 格式化数据
+                result = {}
+                start_addr = command_item['start_addr']
+                length = command_item['length']
+                db_number = "".join(start_addr).split(".")[0]
+                result[db_number] = self.read_batch_data(start_addr, length)
+                # print("-----------------", self._ip, self._port, start_addr, length, result)
+                format_data = self.__converter.convert(self.__data_point_config, result, self.__master)
+                if format_data:
+                    if format_data != "error" and format_data != 'pass':
+                         # 往redis存储数据
+                        self.__storager.real_time_data_storage(format_data)
+                        self._log.info('success -- 实时数据存入redis!')
+
+    def read_batch_data(self, addr, length):
+        try:
+            result = self.__master.Read(addr, length)
+            if result.IsSuccess:
+                datas = result.Content
+                return datas
+            else:
+                if self.__master.ConnectServer().IsSuccess == False:
+                    self.__connected = False
+                    #print("s7 connect falied")
+                else:
+                    self.__connected = True
+                    #print("s7 connect success")
+                return None
+        except Exception as e:
+            print("S7Converter,read[ERROR]:" + str(e))
+            return None
+
+    def writeData(self, address, data_type, data):
+        data_addr = self.address_transform(address)
+        if data_type == "BOOL":
+            data = int(data)
+            self.__master.WriteBool(data_addr, data)
+        elif data_type == "DTL":
+            data_conversion = data.split(" ")
+            data_conversion_date = data_conversion[0].split("-")
+            data_conversion_time = data_conversion[1].split(":")
+            year_h = int(data_conversion_date[0]) >> 8
+            year_l = int(data_conversion_date[0]) - year_h * 256
+            write_month = int(data_conversion_date[1])
+            write_days = int(data_conversion_date[2])
+            write_hours = int(data_conversion_time[0])
+            write_min = int(data_conversion_time[1])
+            write_sec = int(data_conversion_time[2])
+            data_in = bytes([year_h, year_l, write_month, write_days, 0, write_hours, write_min, write_sec, 0, 0, 0, 0])
+            self.__master.Write(data_addr, data_in)
+        elif data_type == "FLOAT32":
+            data = float(data)
+            self.__master.WriteFloat(data_addr, data)
+        elif data_type == "UINT8":
+            data = int(data)
+            self.__master.WriteByte(data_addr, data)
+
+    def readData(self, addr_data, data_type):
+
+        data_addr = self.address_transform(addr_data)
+        if data_type == "BOOL":
+            data_is = self.__master.ReadBool(data_addr).Content  # 读布尔类型
+            return data_is
+        elif data_type == "DTL":
+            data_is = self.__master.Read(data_addr, 12).Content  # 读布尔类型ReadDouble
+            year = int(data_is[0]) * 256 + int(data_is[1])
+            month = int(data_is[2])
+            day = int(data_is[3])
+            hour = int(data_is[5])
+            minute = int(data_is[6])
+            sec = int(data_is[7])
+            times = str(year) + "-" + str(month) + "-" + str(day) + " " + str(hour) + ":" + str(minute) + ":" + str(sec)
+            timeStruct = time.strptime(times, "%Y-%m-%d %H:%M:%S")
+            times = time.strftime("%Y-%m-%d %H:%M:%S", timeStruct)
+            return times
+        elif data_type == "FLOAT":
+            data_is = self.__master.ReadFloat(data_addr).Content
+        elif data_type == "UINT8":
+            data_is = self.__master.ReadByte(data_addr).Content
+        return data_is
+
+    def address_transform(self, addr):
+        real_addr_buffer = "".join(addr).split(".")  # 合并list为字符串 用“.”分割字符串获得数据
+        if real_addr_buffer[1][2] == 'X':
+            data_addr = real_addr_buffer[0] + "." + real_addr_buffer[1][3:] + "." + real_addr_buffer[2]
+        elif real_addr_buffer[1][2] == 'D' or real_addr_buffer[1][2] == 'B':
+            data_addr = real_addr_buffer[0] + "." + real_addr_buffer[1][3:]
+        return data_addr

+ 222 - 0
005_H570/jikong_script/connectors/tcp_connector.py

@@ -0,0 +1,222 @@
+"""
+@Date  :2021/5/21/00219:10:57
+@Desc  :
+"""
+import json
+import time
+import threading
+import socket
+import queue
+from log import OutPutLog
+from connector import Connector
+from event_storage import EventStorage
+from datetime import datetime
+
+class TcpConnector(Connector, threading.Thread):
+    def __init__(self, name, config, converter):
+        super().__init__()
+        self._log = OutPutLog()
+        self.__sock = None
+        self.__connected = False
+        self.__stopped = False
+        self.__size = 1024
+        self.__ip = config['ip']
+        self.__port = config['port']
+        self.__converter = converter
+        self.__storager = EventStorage()
+        self.__save_frequency = config['save_frequency']
+        self.__command_queue = queue.Queue(50)
+        self.setDaemon(True)
+        self._name = name
+        self.setName(name)
+        self.__last_seve_time = 0
+        self.__data_point_config = self.__storager.get_station_info(name)
+        self.__command = self.__storager.get_command_info(name)
+        # print(self.__ip, self.__command, len(self.__command))
+        # print(self.__data_point_config)
+
+    def open(self):
+        self.__stopped = False
+        self.start()
+
+    def run(self):
+        self.__connect()
+        # self.__connected = True
+        while True:
+            time.sleep(1)
+            if len(self.__command) > 0 and isinstance(self.__command, list):
+                if self.__command[0]['command']:
+                    command_list = json.loads(self.__command[0]['command'])
+                    self.command_polling2(command_list)
+            else:
+                self.command_polling()
+            if self.__stopped:
+                break
+
+    # 建立socket连接
+    def __connect(self):
+        if self.__sock:
+            self.close()
+        self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 允许重用本地地址和端口
+        self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)  # 在客户端开启心跳维护
+        # self.__sock.settimeout(180)  # 设置超时时间3mins
+        self.__sock.settimeout(1)  # 设置超时时间3mins
+        try:
+            self.__sock.connect((self.__ip, self.__port))
+            # print(self.__sock)
+            self.__connected = True
+
+            print(datetime.now(), self.__ip, self.__port, "connect success!")
+        except Exception as e:
+            print(datetime.now(), self.__ip, self.__port, "connect failed", e)
+            self.__connected = False
+            self.__reconnect()
+
+    def __reconnect(self):
+        while True:
+            try:
+                self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+                self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)  # 在客户端开启心跳维护
+                # self.__sock.settimeout(180)  # 设置超时时间3mins
+                self.__sock.settimeout(1)  # 设置超时时间3mins
+                self.__sock.connect((self.__ip, self.__port))
+                # print(self.__sock)
+                self.__connected = True
+                print(datetime.now(), self.__ip, self.__port, "reconnect success")
+                break
+            except Exception as e:
+                self.__connected = False
+                print(datetime.now(), self.__ip, self.__port, "reconnect failed", e)
+                time.sleep(5)
+
+    def close(self):
+        """Close the connection with the TCP Slave"""
+        if self.__sock:
+            self.__sock.close()
+            self.__stopped = True
+            self.__sock = None
+            self.__connected = False
+            return None
+
+    def get_name(self):
+        return self.name
+
+    def is_connected(self):
+        return self.__connected
+
+    def send_command(self, data):
+        # bytes.fromhex(each_command)
+        if self.__sock:
+            # print("**************************", self.__ip, type(data),data)
+            try:
+                if isinstance(data, str):
+                    self.__sock.send(bytes.fromhex(data))
+                    return True
+                elif isinstance(data, dict):
+                    command = data["command"]
+                    command = bytes.fromhex(command)
+                    self.__sock.send(command)
+
+                    if "size" in data.keys():
+                        return_command = ""
+                        size = data["size"]  # 接收的指令的长度
+                        while len(return_command) != size:
+                            return_command = self.__sock.recv(size)
+                        return return_command
+
+                    elif "res_command" in data.keys():
+                        return_command = self.__sock.recv(len(command))
+                        res_command = bytes.fromhex(data["res_command"])   # 应该接收到的指令
+                        if res_command == return_command:
+                            return True
+                        else:
+                            return False
+            except Exception as e:
+                print(datetime.now(), self.__ip, "[tcp_connector]send_command error: ", e)
+                self.__connected = False
+                return False
+
+
+    def command_polling(self):
+        if self.__connected:
+            try:
+                time.sleep(0.2)
+                data = self.__sock.recv(self.__size)
+                data = self.__converter.convert(self.__data_point_config, data)
+                print(self.__sock)
+                if data == b'':
+                    self.__reconnect()
+                print(data)
+                if data:
+                    if data != "error" and data != 'pass':
+                        self.__storager.real_time_data_storage(data)
+            except Exception as e:
+                print(f"{datetime.now()} {self.__ip}:{self.__port} {e}")
+                time.sleep(5)
+                self.__connected = False
+                self.__reconnect()
+        else:
+            self.__reconnect()
+
+
+    def command_polling2(self, command_list):
+        if self.__connected:
+            for i in range(len(command_list)):
+                command_item = command_list[i]
+                # print(command_item)
+                if not self.__command_queue.empty():
+                    write_command = self.__command_queue.get()  # 写命令来自数组
+                    try:
+                        res = self.send_command(command=write_command)
+                        print(res)
+                    except Exception as e:
+                        print("mofbus_rtu,write[ERROR]:" + str(e))
+                    # if not res:
+                    #     # 根据(轮询预计用时,剩余可用时间)计算重发次数
+                    #     sent_times = 1
+                    #     while sent_times < resend_times:
+                    #         res = self.exec_command(write_command)
+                    #         sent_times += 1
+                    #         if res:
+                    #             break
+                else:
+                    try:
+                        time.sleep(0.2)
+                        size = command_item["size"]
+                        if isinstance(command_item, dict) and "close_query_status" in command_item.keys():
+                            # 查看水下云台灯的状态
+                            start_query_status = command_item["start_query_status"]      # 查询自清洁部分工作频率及灯开关状态的指令
+                            close_query_status = command_item["close_query_status"]      # 关闭查询的指令
+
+                            result = self.send_command({"size": size, "command": start_query_status})
+
+                            status = 1
+                            while status:
+                                try:
+                                    self.__sock.recv(size)
+                                    self.send_command(close_query_status)
+                                except:
+                                    status = 0
+                        elif "command" in command_item.keys():
+                            result = self.send_command({"size": size, "command": command_item["command"]})
+                            # result = b':\xb3\x1a?\x00\x00\x00B?\x80\xcd\x00<\x01\x01\x01\xf1\xf6'
+                            # print(result)
+
+                        if result:
+                            # print("result = ", result)
+                            format_data = self.__converter.convert(self.__data_point_config, result)
+                            if format_data:
+                                if format_data != "error" and format_data != 'pass':
+                                    # 往redis存储数据
+                                    self.__storager.real_time_data_storage(format_data)
+
+
+                    except Exception as e:
+                        print(datetime.now(), self.__ip, "[tcp_connector]command_polling2 error: ", e)
+                        time.sleep(5)
+                        # self.__reconnect()x
+        else:
+            self.__reconnect()
+

+ 8 - 0
005_H570/jikong_script/converter.py

@@ -0,0 +1,8 @@
+from abc import ABC, abstractmethod
+
+
+class Converter(ABC):
+
+    @abstractmethod
+    def convert(self, config, data):
+        pass

+ 6 - 0
005_H570/jikong_script/converters/__init__.py

@@ -0,0 +1,6 @@
+from . import modbus_converter
+from . import shucai_converter
+from . import s7_converter
+from . import a1e_converter
+from . import pass_converter
+from . import tcp_converter

+ 42 - 0
005_H570/jikong_script/converters/a1e_converter.py

@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 11:37
+@desc: sct003 和 moxae1210 的解析器
+"""
+
+
+from converter import Converter
+from log import OutPutLog
+
+class A1eConverter(Converter):
+
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def convert(self, config, data, master):
+        if data:
+            format_data_dict = {}  # 列表数据转换字典数字
+            try:
+                for index in config:
+                    type = index['data_type']
+                    address = index['address']
+                    data_addr = int(address[1:])*2
+                    db_number = address[:1]
+                    if db_number in data:
+                        if data[db_number] != None : #防止设备断线返回为空导致的异常
+                            if data_addr < len(data[db_number]):
+                                if type == "UINT16":
+                                    return_data = master.byteTransform.TransUInt16(data[db_number], data_addr)
+                                elif type == "INT32":
+                                    return_data = master.byteTransform.TransInt32(data[db_number], data_addr)
+                                name = 'c' + str(index['serial_number'])
+                                if index['divisor'] is not None:
+                                    return_data = return_data * index['divisor']
+                                if isinstance(return_data, float):
+                                    return_data = round(return_data, 2)
+                                format_data_dict[name] = return_data
+            except Exception as e:
+                print("A1EConverter[ERROR]:"+str(e))
+                return "error"
+            return format_data_dict

+ 149 - 0
005_H570/jikong_script/converters/modbus_converter.py

@@ -0,0 +1,149 @@
+from converter import Converter
+import struct
+import binascii
+from log import OutPutLog
+from event_storage import EventStorage
+
+
+class ModbusConverter(Converter):
+    list = []
+
+    def __init__(self):
+        self._log = OutPutLog()
+        self._storage = EventStorage()
+
+
+    def convert(self, config, data):
+        """
+        :param config: [{'id': 27, 'station_name': 'modbustcptest' ...}, {'id': 28, 'station_name': 'modbustcptest' ...} ..]
+        :param data: [0, 1, 2, 3, 4, 5, 6, 7, 65535, 0, 65535]
+        :return: {'c201': 0, 'c202': 1, 'c203': 2, 'c204': 3, 'c205': 4, 'c206': 5 ...}
+        """
+        if data:
+            device_id = data[0]
+            data = data[1]
+            format_data_dict = {}  # 列表数据转换字典数字
+            try:
+                # print(len(data), "data = ", data)
+                for index in config:
+                    if int(index["device_id"]) == int(device_id):
+                        # addr_type : 'D' 或 'X';
+                        # addr_list: [10] 或 [10, 5]
+                        addr_type, addr_list = addr_parsing(index['address'])
+                        register_addr = addr_list[0]  # 数据地址  example:'X10.5' -> 10
+
+                        if register_addr > 40000:
+                            register_addr = register_addr - 40001
+
+                        if register_addr in data:
+                            name = 'c' + str(index['serial_number'])
+                            if addr_type == "R":
+                                # 从redis获取数据
+                                real_data = self._storage.get_real_data([name])
+                                if real_data:
+                                    return_data = real_data[name]
+                                else:
+                                    return_data = False
+                            elif addr_type == 'X':
+                                bit_offset_addr = addr_list[1]  # 位偏移地址  example:'X10.5' -> 5
+                                if index['data_type'] == "BOOL":
+                                    data_bin = bin(65536 | data[register_addr])  # 和65536做或运算,为了留开头0
+                                    data_bin = list(data_bin[3:][::-1])  # 去除开头字符 0  b  1并反转字符串
+                                    data_bin = list(map(int, data_bin))  # 字符列表转整型列表
+                                    if index['modbus_mode'] == "BA":
+                                        data_bin = data_bin[8:16] + data_bin[0:8]
+                                    if index['negation'] == 1:
+                                        return_data = int(bool(1-data_bin[bit_offset_addr])) #取反运算
+                                    else:
+                                        return_data = data_bin[bit_offset_addr]
+
+                            elif addr_type == 'D':
+                                if index['data_type'] == "FLOAT16":
+                                    return_data = data[register_addr]
+                                elif index['data_type'] == "INT16":
+                                    if index['negation'] == 1:
+                                        return_data = int(bool(1-data[register_addr])) #取反运算
+                                    else:
+                                        if data[register_addr] > 32767:
+                                            return_data = data[register_addr] - 65536
+                                        else:
+                                            return_data = data[register_addr]
+                                elif index['data_type'] == "UINT16":
+                                    if index['negation'] == 1:
+                                        return_data = int(bool(1-data[register_addr])) #取反运算
+                                    else:
+                                        return_data = data[register_addr]
+                                elif index['data_type'] == "INT32":
+                                    return_data_H = data[register_addr]
+                                    return_data_L = data[register_addr + 1]
+                                    if index['modbus_mode'] == "CDAB":
+                                        return_data = data[register_addr] * 65536 + data[register_addr+1]
+                                    else:
+                                        return_data = data[register_addr + 1] * 65536 + data[register_addr]
+                                elif index['data_type'] == "FLOAT32":
+                                    t1 = hex(data[register_addr])[2:]
+                                    t2 = hex(data[register_addr+1])[2:]
+                                    if len(t1) < 4:
+                                        t1 = (4-len(t1)) * "0" + t1
+                                    if len(t2) < 4:
+                                        t2 = (4 - len(t2)) * "0" + t2
+
+                                    if index['modbus_mode'] == "CDAB":
+                                        return_data = struct.unpack('>f', binascii.unhexlify((t2+t1).replace(' ', '')))[0]
+                                    else:
+                                        return_data = struct.unpack('>f', binascii.unhexlify((t1+t2).replace(' ', '')))[0]
+                                elif index['data_type'] == "BELZ_FLOAT32":
+                                    llj_data = []
+                                    for x in range(0, 6, 2):
+                                        t1 = hex(data[register_addr+x])[2:]
+                                        t2 = hex(data[register_addr+x+1])[2:]
+                                        if len(t1) < 4:
+                                            t1 = (4 - len(t1)) * "0" + t1
+                                        if len(t2) < 4:
+                                            t2 = (4 - len(t2)) * "0" + t2
+                                        t = struct.unpack('>f', binascii.unhexlify((t1 + t2).replace(' ', '')))[0]
+                                        llj_data.append(t)
+                                    return_data = llj_data[0] * 10**6 + llj_data[1] + llj_data[2]/10**6        # 总累计量
+
+
+                                # 先乘除
+                                if index['divisor'] is not None:
+                                    return_data = return_data * index['divisor']
+                                # 再加减
+                                if index['offset'] is not None:
+                                    return_data = return_data + index['offset']
+
+                                if isinstance(return_data, float):
+                                    return_data = round(return_data, 2)
+                            # name = 'c' + str(index['serial_number'])
+                            ##################################
+                            #f str(index['serial_number']) == index['device_id'] or index['device_id'] == '0':
+                            #  format_data_dict[name] = return_data
+                            #else:
+                            #    com_name = 'c' + index['device_id']
+                            #    list_com_name = [com_name]
+                            #    status_list = self._storage.get_real_data(list_com_name)
+                            #    status = status_list[com_name]
+                            #    if status == '0':
+                            #        format_data_dict[name] = return_data
+                            ###################################
+                            format_data_dict[name] = return_data
+                # print("format_data_dict = ", format_data_dict)
+                return format_data_dict
+            except Exception as e:
+                print("[ERROR:ModbusConverter]-", e)
+                self._log.error(e)
+                return "error"
+
+
+def addr_parsing(addr_smash):
+    """
+    :param addr_smash: [X15.1] or [D15]
+    :return: X, [15, 1] or D [15]
+    """
+    # addr_smash_1 = 'D2'
+    # addr_smash = list(addr_smash)  # 拆分字符串为list ['X', '6', '.', '2']
+    addr_type = addr_smash[0]  # 地址类型 : 'D' 或 'X'
+    addr_smash = addr_smash[1:]  # 地址部分: '10' 或 '10.5'
+    addr_list = list(map(int, addr_smash.split(".")))  # 用“.”分割字符串转换为整型存入列表
+    return addr_type, addr_list

+ 9 - 0
005_H570/jikong_script/converters/pass_converter.py

@@ -0,0 +1,9 @@
+import json
+import re
+from converter import Converter
+
+
+class PassConverter(Converter):
+
+    def convert(self, config, data):
+        return "pass"

+ 73 - 0
005_H570/jikong_script/converters/s7_converter.py

@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*-
+
+from converter import Converter
+from log import OutPutLog
+
+class S7Converter(Converter):
+
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def convert(self, config, data, master):
+        # print(data)
+        if data:
+            format_data_dict = {}  # 列表数据转换字典数字
+            try:
+                for index in config:
+                    address = index['address']
+                    if address.startswith("DB"):
+                        # data =  {'DB13': bytearray(b"A\xc8\x00\x00A\xd2A\xeeB\x08\x00\x00=tq\xc7B\x00\x00\x00B\x06\x86\xe3?\x04\x12\xb9?\x0c\xcc\xcd=L\xcc\xcd>\xcc\xcc\xcd?\x00\x00\x00\x00\x00\x01\r>\xa8j1?\x0c\xcc\xcd=L\xcc\xcd=\xcc\xcc\xcd?\x00\x00\x00\x00\x00\x01\x1a\x00\x00\x00\x01?\r\x88p?\x80\x00\x00>L\xcc\xcd?333?5\xc2\x8fA\x07\xb8\x90A\xa0\x00\x00\x00\x00\x00\x00@KC\x96\x00\x00\x00\x00A\xce\xcc\xcdB\x0c\x00\x00Ap\x00\x00B?\xa3\xd7B\xc6\x00\x00\x00\x00\x00\x00A\xc8\x00\x00A \x00\x00A\xbc\x1a\xe0A\xd0\x00\x00A\x80\x00\x00A\x10v\xfb?\x88X\x82Ap\x00\x00A\x08\x00\x00@\xa0\x00\x00A\xa6\x14{A\x18\x00\x00@\xe2p\x92A\x10\x00\x00\x00\x00\x00\x00Az\xdc\x80Dy\xc0\x00\xc4y\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\xcaJp\x00\x00\x00\x00\x00\x00\x00\x00A\x06\x9aGAp\x00\x00@\xa0\x00\x00@\xc9\xd8\xe4A`\x00\x00\x00\x00\x00\x00\xc1\xb2d\x80Dy\xc0\x00\xc4y\xc0\x00A\xc8\x00\x00A\xc8\x00\x00A\xc8\x00\x00A\xf4\x00\x00A\xc8\x00\x00\x01\x00Ap\x00\x00\x01\x00\x19\x0f\x01\x00Cf\xb33ChfgCi\xb33C\xc8\x8c\xcdC\xc9&gC\xc9\xd9\x9aA)G\xaf@\xe4\xcc\xce?\xd9\x99\x9bElF{\x00\x00\x00\x00\x00Z@\xdc\xcc\xcd?fffC\x05\x00\x00D\x18@\x00\x00\x01\x00\x00\x00\x00\x00Z\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\'GJ\x00D\x80\xc3\x04\x00\n\x90\x82\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x88\xa3\xd7\x00\x00?^\xa1T?\x80\x00\x00>L\xcc\xcd\x04\x00A\xca\x0f\x00")}
+                        addr = self.address_transform(address)     # 以 DB13.DBX395.1 为例:DB13.395.1
+                        addr_division = "".join(addr).split(".")            # ['DB13', '395', '1']
+                        db_number = addr_division[0]                        # DB13
+                        data_addr = int(addr_division[1])                   # 395
+
+                    elif address.startswith("M") or address.startswith("I"):
+                        # data =  {'M0': bytearray(b'\xc0\x04')}
+                        addr_division = address.split(".")  # 以"M20.6"为例,["M20", "6"]
+                        db_number = addr_division[0]
+                        data_addr = 0
+
+                    elif address.startswith("VD") or address.startswith("VW"):
+                        db_number = address
+                        data_addr = 0
+
+                    if db_number in data:
+                        if data[db_number] != None : #防止设备断线返回为空导致的异常
+                            if data_addr < len(data[db_number]):
+                                type = index['data_type']
+                                if type == "FLOAT32":
+                                    return_data = master.byteTransform.TransSingle(data[db_number], data_addr)
+                                elif type == "BOOL":
+                                    return_data = int(master.byteTransform.TransBoolArray(data[db_number], data_addr, 1)[int(addr_division[-1])])
+                                    # return_data = int(master.byteTransform.TransBoolArray(data[db_number], data_addr, 1)[int(addr_division[2])])
+                                elif type == "UINT8":
+                                    return_data = master.byteTransform.TransByte(data[db_number], data_addr)
+                                elif type == "USINT":
+                                    return_data = master.byteTransform.TransByte(data[db_number], data_addr)
+                                elif type == "INT32":
+                                    # INT32:DInt类型
+                                    return_data = master.byteTransform.TransInt32(data[db_number], data_addr)
+                                elif type == "INT16":
+                                    # INT16:Int类型
+                                    return_data = master.byteTransform.TransInt16(data[db_number], data_addr)
+
+                                if isinstance(return_data, float):
+                                    return_data = round(return_data, 2)
+                                name = 'c' + str(index['serial_number'])
+                                format_data_dict[name] = return_data
+
+                # print("format_data_dict", format_data_dict)
+            except Exception as e:
+                print(data.keys(), "S7Converter[ERROR]:"+str(e))
+                return "error"
+            return format_data_dict
+
+    def address_transform(self, addr):
+        real_addr_buffer = "".join(addr).split(".")  # 合并list为字符串 用“.”分割字符串获得数据
+        if real_addr_buffer[1][2] == 'X':
+            data_addr = real_addr_buffer[0] + "." + real_addr_buffer[1][3:] + "." + real_addr_buffer[2]
+        elif real_addr_buffer[1][2] == 'D' or real_addr_buffer[1][2] == 'B' or real_addr_buffer[1][2] == 'W':
+            data_addr = real_addr_buffer[0] + "." + real_addr_buffer[1][3:]
+        return data_addr

+ 30 - 0
005_H570/jikong_script/converters/shucai_converter.py

@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@time: 2021/5/31 11:37
+@desc: sct003 和 moxae1210 的解析器
+"""
+
+
+from converter import Converter
+from log import OutPutLog
+
+class ShucaiConverter(Converter):
+
+    def __init__(self):
+        self._log = OutPutLog()
+
+    def convert(self, config, data):
+        if data:
+            try:
+                format_data_dict = {}
+                for index in config:
+                    name = 'c' + str(index['serial_number'])
+                    if data[index['address']] != None:
+                        format_data_dict[name] = data[index['address']]
+                return format_data_dict
+            except Exception as e:
+                print(e)
+                self._log.error(e)
+                return "error"
+

+ 122 - 0
005_H570/jikong_script/converters/tcp_converter.py

@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/30 11:01
+@Author: lxc
+@LastEditTime:
+@Desctiption:
+"""
+
+
+from converter import Converter
+import struct
+import binascii
+from log import OutPutLog
+from event_storage import EventStorage
+
+
+class TcpConverter(Converter):
+    list = []
+
+    def __init__(self):
+        self._log = OutPutLog()
+        self._storage = EventStorage()
+
+
+    def convert(self, config, data):
+        """
+        :param config: [{'id': 27, 'station_name': 'modbustcptest' ...}, {'id': 28, 'station_name': 'modbustcptest' ...} ..]
+        :param data: b'\xaa\x88\x00\x00\x01\x00U'
+        :return: {'c201': 0, 'c202': 1, 'c203': 2, 'c204': 3, 'c205': 4, 'c206': 5 ...}
+        """
+        # print(config)
+        # print("data = ", data)    #  b'\x01\x03\x10\x9b\x03\x9b\xba\x96N\x9c\xf3\x97;\x00\x00\x9f\xa5\x00\x000\x0b'
+        if data:
+            format_data_dict = {}  # 列表数据转换字典数字
+            try:
+                print(len(data), "data = ", data)
+                for index in config:
+                    # addr_type : 'D' 或 'X';
+                    # addr_list: [10] 或 [10, 5]
+                    addr_type, addr_list = addr_parsing(index['address'])
+                    register_addr = addr_list[0]  # 数据地址  example:'X10.5' -> 10
+
+                    if len(data) > register_addr:
+                        name = 'c' + str(index['serial_number'])
+                        if addr_type == "R":
+                            # 从redis获取数据
+                            real_data = self._storage.get_real_data([name])
+                            if real_data:
+                                return_data = real_data[name]
+                            else:
+                                return_data = False
+                        if addr_type == 'D':
+                            if index['data_type'] == "INT16":
+                                return_data = data[register_addr]
+
+                            elif index['data_type'] == "UINT32":
+                                '''Unsigned int:无符号整形'''
+                                t1 = hex(data[register_addr])[2:]
+                                t2 = hex(data[register_addr + 1])[2:]
+                                if len(t1) < 2:
+                                    t1 = (2 - len(t1)) * "0" + t1
+                                if len(t2) < 2:
+                                    t2 = (2 - len(t2)) * "0" + t2
+
+                                if index['modbus_mode'] == "BA":
+                                    t = t2 + t1
+                                else:
+                                    t = t1 + t2
+                                return_data = int(t, 16)
+
+                            elif index['data_type'] == "UCHAR":
+                                '''Unsigned char:无符号字节'''
+                                return_data = data[register_addr]
+
+                            elif index['data_type'] == "FLOAT64":
+                                t1 = hex(data[register_addr])[2:]
+                                t2 = hex(data[register_addr + 1])[2:]
+                                t3 = hex(data[register_addr + 2])[2:]
+                                t4 = hex(data[register_addr + 3])[2:]
+                                if len(t1) < 2:
+                                    t1 = (2 - len(t1)) * "0" + t1
+                                if len(t2) < 2:
+                                    t2 = (2 - len(t2)) * "0" + t2
+                                if len(t3) < 2:
+                                    t3 = (2 - len(t3)) * "0" + t3
+                                if len(t4) < 2:
+                                    t4 = (2 - len(t4)) * "0" + t4
+                                return_data = struct.unpack('>f', bytes.fromhex(t1 + t2 + t3 + t4))[0]  # 小端
+                                # return_data = struct.unpack('>f', binascii.unhexlify((t1 + t2 + t3 + t4).replace(' ', '')))[0
+
+
+                            # 先乘除
+                            if index['divisor'] is not None:
+                                return_data = return_data * index['divisor']
+                            # 再加减
+                            if index['offset'] is not None:
+                                return_data = return_data + index['offset']
+                            if isinstance(return_data, float):
+                                return_data = round(return_data, 2)
+                        # name = 'c' + str(index['serial_number'])
+                        if return_data:
+                            format_data_dict[name] = return_data
+                print("format_data_dict = ", format_data_dict)
+                return format_data_dict
+            except Exception as e:
+                print("[TcpConverter ERROR] ", e)
+                self._log.error(e)
+                return "error"
+
+
+def addr_parsing(addr_smash):
+    """
+    :param addr_smash: [X15.1] or [D15]
+    :return: X, [15, 1] or D [15]
+    """
+    # addr_smash_1 = 'D2'
+    # addr_smash = list(addr_smash)  # 拆分字符串为list ['X', '6', '.', '2']
+    addr_type = addr_smash[0]  # 地址类型 : 'D' 或 'X'
+    addr_smash = addr_smash[1:]  # 地址部分: '10' 或 '10.5'
+    addr_list = list(map(int, addr_smash.split(".")))  # 用“.”分割字符串转换为整型存入列表
+    return addr_type, addr_list

+ 71 - 0
005_H570/jikong_script/creat_tbl.py

@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2022/06/27 09:28
+@Author: lxc
+@LastEditTime: 
+@Desctiption:
+"""
+
+
+
+from event_storage import EventStorage
+from log import OutPutLog
+
+
+
+save_log = OutPutLog()
+operate_mysql = EventStorage()
+
+
+def creatr_table():
+    # select_all_device_sql = "SELECT DISTINCT(device_name) FROM `data_point_tbl`;"
+    select_all_device_sql = "SELECT DISTINCT(device_name) FROM `data_point_tbl` WHERE `device_name` LIKE '%_electric';"
+    all_device = operate_mysql.execute_sql(select_all_device_sql)
+    for device in all_device:
+        device_name = device["device_name"]
+        table_name = "table_" + device_name
+        create_sql = f"CREATE TABLE `{table_name}` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`times` datetime NOT NULL,"
+
+
+        select_point_sql = f"SELECT serial_number,storage_type FROM `data_point_tbl` WHERE device_name=\'{device_name}\';"
+        all_point = operate_mysql.execute_sql(select_point_sql)
+        for point in all_point:
+            serial_number = "c" + str(point["serial_number"])
+            storage_type = point["storage_type"]
+            create_sql = create_sql + f"`{serial_number}` {storage_type} DEFAULT NULL,"
+
+        create_sql = create_sql + "  `is_send` tinyint(4) NOT NULL DEFAULT '0',PRIMARY KEY (`id`),KEY `times` (`times`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
+
+        res = operate_mysql.execute_update_sql(create_sql)
+
+        print(res, table_name)
+        # save_log.info(f"{res, device_name}")
+        # save_log.info(create_sql)
+
+
+creatr_table()
+
+
+
+
+
+"""
+CREATE TABLE `table_dbqycfpffj_electric` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `times` datetime NOT NULL,
+  `c631` float DEFAULT NULL,
+  `c632` float DEFAULT NULL,
+  `c633` float DEFAULT NULL,
+  `c634` float DEFAULT NULL,
+  `c635` float DEFAULT NULL,
+  `c636` float DEFAULT NULL,
+  `c637` float DEFAULT NULL,
+  `c638` float DEFAULT NULL,
+  `c639` float DEFAULT NULL,
+  `c640` float DEFAULT NULL,
+  `is_send` tinyint(4) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  KEY `times` (`times`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+"""

+ 77 - 0
005_H570/jikong_script/event_storage.py

@@ -0,0 +1,77 @@
+import json
+import re
+from memory_storage import MemoryStorage
+from hard_disk_storage import HardDiskStorage
+from configuration import Configuration
+
+class EventStorage:
+    def __init__(self):
+        self.config = Configuration().get_system_config()
+        self.memoryStorage = MemoryStorage(self.config['memoryDatabase'])
+        self.hardDiskStorage = HardDiskStorage(self.config['hardDiskdataBase'])
+
+    def get_real_data(self, keys):
+        data = self.memoryStorage.get_value(keys)
+        return data
+
+    def get_historical_data(self, select_info):
+        data = self.hardDiskStorage.get_table_data(select_info)
+        return data
+
+    def real_time_data_storage(self, data):
+        self.memoryStorage.set_value(data)
+
+    def historical_data_storage(self, table_name, seve_time, data):
+        self.hardDiskStorage.insert_column_many(table_name, seve_time, data)
+
+    def get_connector_config(self, read_write):
+        config = self.hardDiskStorage.get_connectors(read_write)
+        for station_info in config:
+            station_info['connector_config'] = json.loads(station_info['connector_config'])
+        return config
+
+    def get_station_info(self, station_name):
+        return self.hardDiskStorage.get_station_info(station_name)
+
+    def get_table_name(self):
+        table_name = self.hardDiskStorage.get_table_name()
+        return table_name
+
+    # def table_xxx_insert_data(self, format_data_dict, table_name, save_time):
+    #     self.hardDiskStorage.table_xxx_insert_data(format_data_dict, table_name, save_time)
+
+    def get_point_info(self, keys):
+        point_list = []
+        if keys:
+            for key in keys:
+                point_list.append(re.sub("\D", "", key))
+            point_tuple = tuple(point_list)
+        else:
+            point_tuple = None
+        return self.hardDiskStorage.get_point_info(point_tuple)
+
+    # 获取modbus命令
+    def get_command_info(self, station_name):
+        return self.hardDiskStorage.get_command_info(station_name)
+
+    # 执行sql语句
+    def execute_sql(self, sql):
+        result = self.hardDiskStorage.execute_sql(sql)
+        return result
+
+    def execute_update_sql(self, sql):
+        """执行UPDATE、INSERT、DELETE语句"""
+        return self.hardDiskStorage.execute_update_sql(sql)
+
+    def gather_fish_light_info(self, location):
+        """水下聚鱼灯远程控制功能:查找指定位置的聚鱼灯的相关控制信息"""
+        return self.hardDiskStorage.gather_fish_light_info(location)
+
+    def get_gather_fish_light_command(self):
+        """水下聚鱼灯远程控制功能:查看控制聚鱼灯的指令"""
+        return self.hardDiskStorage.get_gather_fish_light_command()
+          
+
+class Networkerror(RuntimeError):
+    def __init__(self, arg):
+        self.args = arg

+ 150 - 0
005_H570/jikong_script/feeding_statistics.py

@@ -0,0 +1,150 @@
+"""
+@Date  :2021/6/16/14:47
+@Author:zz
+@Desc  :投喂数据统计
+"""
+
+import time
+import json
+import threading
+import traceback
+
+from event_storage import EventStorage
+from utility import Utility
+from log import OutPutLog
+from apis.get_feeding_advise import GetFeedingAdvise
+
+
+class FeedingStatistics:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+        self._run_time = None
+        self._feed_id = None
+
+    def str_to_flaot(self, str):
+        if str != None:
+            return float(str)
+        else:
+            return 'null'
+
+    # 历史存储主函数
+    def run(self):
+        self._log.info('[AutoFeeding] - FeedingStatistics module is running!')
+        # 风向:c1,风速:c2,流速:c7,流向:c8
+        # 罗茨风机1号运行频率:c441
+        # 罗茨风机2号运行频率:c442
+        # 罗茨风机3号运行频率:c443
+        # 罗茨风机4号运行频率:c444
+        # 旋转输料器1号运行频率:c445
+        # 旋转输料器2号运行频率:c446
+        # 旋转输料器3号运行频率:c447
+        # 旋转输料器4号运行频率:c448
+        # 线路4-1运行:c572
+        # 线路4-2运行:c573
+        # 线路4-3运行:c574
+        # 线路4-4运行:c575
+        # 线路4-5运行:c576
+        list = ["c1", "c2", "c7", "c8", "c441", "c442", "c443", "c444", "c445", "c446", "c447", "c448", "c572", "c573", "c574", "c575", "c576"]
+
+        # 获取配置信息
+        while 1:
+            time.sleep(2)
+            real_data_dict = self._storage.get_real_data(list)
+
+            for key in real_data_dict:
+                if real_data_dict[key] == None:
+                    real_data_dict[key] = 0
+
+            # 记录投喂过程
+            try:
+                feeder_frequency = 0
+                # 判断供料器和投饵口
+                if float(real_data_dict['c445']) > 1:
+                    feeder_frequency = float(real_data_dict['c445'])
+                    tank_number = 1
+                    feeding_port = 101
+                elif float(real_data_dict['c446']) > 1:
+                    feeder_frequency = float(real_data_dict['c446'])
+                    tank_number = 2
+                    feeding_port = 201
+                elif float(real_data_dict['c447']) > 1:
+                    feeder_frequency = float(real_data_dict['c447'])
+                    tank_number = 3
+                    feeding_port = 301
+                elif float(real_data_dict['c448']) > 1:
+                    feeder_frequency = float(real_data_dict['c448'])
+                    tank_number = 4
+                    if int(real_data_dict['c572']) == 1:
+                        feeding_port = 401
+                    elif int(real_data_dict['c573']) == 1:
+                        feeding_port = 402
+                    elif int(real_data_dict['c574']) == 1:
+                        feeding_port = 403
+                    elif int(real_data_dict['c575']) == 1:
+                        feeding_port = 404
+                    elif int(real_data_dict['c576']) == 1:
+                        feeding_port = 405
+                else:
+                    self._feed_id = None
+
+                # 判断风机
+                if float(real_data_dict['c441']) > 0:
+                    fen_frequency = float(real_data_dict['c441'])
+                elif float(real_data_dict['c442']) > 0:
+                    fen_frequency = float(real_data_dict['c442'])
+                elif float(real_data_dict['c443']) > 0:
+                    fen_frequency = float(real_data_dict['c443'])
+                elif float(real_data_dict['c444']) > 0:
+                    fen_frequency = float(real_data_dict['c444'])
+
+                if feeder_frequency > 1:
+                    now_time = time.time()
+                    if self._feed_id == None:
+                        self._feed_id = 1
+                        feed_id = int(now_time)
+                    if self._run_time == None:
+                        self._run_time = int(now_time)
+                    save_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(now_time))
+                    wind_speed = self.str_to_flaot(real_data_dict['c2'])
+                    wind_direction = self.str_to_flaot(real_data_dict['c1'])
+                    flow_speed = self.str_to_flaot(real_data_dict['c7'])
+                    flow_direction = self.str_to_flaot(real_data_dict['c8'])
+
+                    sql_get_task_info = "SELECT * FROM touer_set;"
+                    task_info = self._storage.execute_sql(sql_get_task_info)
+                    task_info = task_info[0]
+                    if task_info['feed_mode'] == 1:
+                        feeding_mode = "自动"
+                    elif task_info['feed_mode'] == 0:
+                        feeding_mode = "手动"
+                    else:
+                        feeding_mode = None
+                    breed = task_info['feed_kind']
+                    tank_number_info = eval(task_info["tank1"])
+                    bait_name = tank_number_info['name']
+                    feed_weight = float(tank_number_info['weight'])
+                    feed_diameter = int(tank_number_info['diameter'])
+                    shelf_life = tank_number_info['shelf_life']
+                    feeding_speed = 1440 / 67 * feeder_frequency / 50 * (8 - 0.5 * feed_diameter) * 1 / 60
+                    now_time = int(time.time())
+                    feeding_amount = round(feeding_speed * (now_time - self._run_time), 2)
+                    self._run_time = now_time
+
+                    sql = "INSERT INTO fishery_data(feed_id, times, wind_speed, wind_direction,\
+                           flow_speed, flow_direction, feeding_port, tank_number, feeder_frequency,\
+                           fan_frequency, feeding_amount, feeding_mode, breed, bait_name, feed_weight, feed_diameter, shelf_life) \
+                           VALUES (%s,'%s',%s,%s,%s,%s,%s,%s,%s,%s,%s,'%s','%s','%s',%s,%s,'%s')" % \
+                          (feed_id, save_time, wind_speed, wind_direction, flow_speed, flow_direction, feeding_port, \
+                           tank_number, feeder_frequency, fen_frequency, feeding_amount, feeding_mode, breed, bait_name,
+                           feed_weight, feed_diameter, shelf_life)
+
+                    #print(sql)
+                    self._storage.execute_sql(sql)
+                else:
+                    self._run_time = None
+                    self._feed_id = None
+            except Exception as e:
+                print('行号', e.__traceback__.tb_lineno)
+                print("get fishery_data [ERROR]:" + str(e))
+                self._log.error("get fishery_data [ERROR]:" + str(e))

+ 260 - 0
005_H570/jikong_script/gateway.py

@@ -0,0 +1,260 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*-
+"""
+@desc: 连接器:可读,可写
+"""
+
+import time
+import threading
+from sanic import Sanic
+from sanic_cors import CORS, cross_origin
+from sanic import response
+from event_storage import EventStorage
+from utility import Utility
+from historical_data_storage import HistoricalDataStorage
+from feeding_statistics import FeedingStatistics
+from auto_feeding import AutoFeeding
+from auto_charge import AutoCharge
+from alarm import Alarm
+from api_context import ApiContext
+from update_maintenance_info import UpdateMaintenanceInfo
+from auto_switch_device import AutoSwitchDevice
+from alarm_buzzer import AlarmBuzzer
+from alarm_record import AlarmRecord
+from auto_switch_juyudeng import AutoSwitchJuyudeng
+from auto_switch_yuntaideng import AutoSwitchYuntaideng
+from auto_profile_1501 import AutoProfile1501
+from reset_remote_control import ResetRemoteControl
+from get_laliji_param import GetLalijiParam
+from datetime import datetime
+
+app = Sanic(__name__)
+CORS(app)
+
+
+gateway_storage = EventStorage()
+connector_config = gateway_storage.get_connector_config(read_write=0)
+Utility.start_connectors(connector_config)
+
+
+@app.route('/readRealText', methods=['POST'])
+async def read_point_data_text(request):
+    list = request.json['pointList']
+    dict = gateway_storage.get_real_data(list)
+    point_list = gateway_storage.get_point_info(list)
+    data_list = {}
+    for info in point_list:
+        data_list[info['io_point_name']] = str(dict["c"+str(info['serial_number'])]) + " " +str(info['unit'])
+    return response.json(data_list)
+
+@app.route('/readReal', methods=['POST'])
+async def read_point_data(request):
+    list = request.json['pointList']
+    dict = gateway_storage.get_real_data(list)
+    '''
+    data_list = gateway_storage.get_point_info(list)
+    for info in data_list:
+        info['value'] = dict["c"+str(info['serial_number'])]
+    '''
+    return response.json(dict)
+
+
+@app.route('/api', methods=['POST'])
+async def read_statistics_data(request):
+    if len(request.json) > 0:
+        list = []
+        for index in range(len(request.json)):
+            api_object = request.json[index]['apiObject']
+            parameter = request.json[index]['parameter']
+            api = ApiContext()
+            api.set_api_object(api_object)
+            result = api.operation(parameter)
+            list.append(result)
+        data_json = Utility.data_encoder(list)
+        return response.text(data_json)
+
+@app.route('/write',methods=['POST'])
+async def write_data(request):
+    t1 = time.time()
+    station_name = request.json["station_name"]
+    command = request.json["command"]
+    try:
+        result = Utility.available_connectors[station_name].send_command(command)
+        return response.json({'message': result})
+    except Exception as e:
+        print(station_name+"write[ERROR]:" + str(e))
+        return response.json({'message': result})
+
+
+
+
+@app.route('/modbus/fdj', methods=['POST'])
+async def write_data(request):
+    """
+    远程控制发电机启停
+    @param request: {"device":"1", "deviceStatus":"start"}
+    @return:
+    """
+    device = request.json["device"]                 # 1=主发电机,2=应急发电机
+    device_status = request.json["deviceStatus"]     # start和stop
+
+    # 判断设备能否远程控制
+    if device in ["1", "2"] and device_status in ["start", "stop"]:
+        device_status, real_data_dict = judge_fdj_status(device, device_status)
+
+        if device_status is True:
+            station_name, command = get_station_name_command(device, device_status)
+            try:
+                # 测试,先注释
+                # result = Utility.available_connectors[station_name].send_command(command)
+                result = "success"
+                res = "success"
+                log_info = f"result={result}"
+            except Exception as e:
+                res = "failure"
+                log_info = f"contorl error, e={e}"
+        else:
+            res = "failure"
+            log_info = f"device_status={device_status}, real_data_dict={real_data_dict}"
+    else:
+        res = "failure"
+        log_info = "传参错误"
+
+    save_log("control", f"fdj: request={request.json}, res={res}, {log_info}")
+
+    return response.json({'message': res})
+
+
+
+def judge_fdj_status(device, operation):
+    """
+    判断设备状态
+    c411 主发电机 系统工作模式(0:本地模式,1:遥控模式,2:自动模式)
+    c815 主发电机 备车信号(0=否,1=是)
+    c402 主发电机 运行(0=否,1=是)
+
+    c432 应急发电机 系统工作模式(0:本地模式,1:遥控模式,2:自动模式)
+    c817 应急发电机 备车信号(0=否,1=是)
+    c423 应急发电机 运行(0=否,1=是)
+    @param device: 1=主发电机 2=应急发电机
+    @param operation:start=启动 stop=停止
+    @return:
+    """
+
+    point_list = ["c411", "c815", "c402", "c432", "c817", "c423"]
+    real_data_dict = gateway_storage.get_real_data(point_list)
+    # real_data_dict = {"c411": "2", "c815": "1", "c402": "1", "c432": "2", "c817": "0", "c423": "0"}
+
+    if device == "1":
+        # 控制主发电机:自动模式(c411)
+        control_mode = real_data_dict["c411"]
+        bc_status = real_data_dict["c815"]
+        run_status = real_data_dict["c402"]
+    elif device == "2":
+        # 控制应急发电机:自动模式(c432)
+        control_mode = real_data_dict["c432"]
+        bc_status = real_data_dict["c817"]
+        run_status = real_data_dict["c423"]
+
+
+    if operation == "start":
+        # 主发启动:自动模式(c411)、备车信号(c815)、未运行(c402)
+        # 应发启动:自动模式(c432)、备车信号(c817)、未运行(c423)
+        if control_mode == "2" and bc_status == "1" and run_status == "0":
+            res = True
+        else:
+            res = f"Failed: 设备状态错误"
+    elif operation == "stop":
+        # 主发停止:自动模式(c411)、正在运行(c402)
+        # 应发停止:自动模式(c432)、正在运行(c423)
+        if control_mode == "2" and run_status == "1":
+            res = True
+        else:
+            res = f"Failed: 设备状态错误"
+
+    return res, real_data_dict
+
+
+
+def get_station_name_command(device, operation):
+    """
+    查询指令
+    @param device:1=主发电机 2=应急发电机
+    @param operation:start=启动 stop=停止
+    @return:
+    """
+    if device == "1" and operation == "start":
+        station_name = "remote_control"
+        command = [{"device_id": 1, "start_addr": 3, "output_value": 65280, "function_code": 5, "res": 65280}]
+    elif device == "1" and operation == "stop":
+        station_name = "remote_control"
+        command = [{"device_id": 1, "start_addr": 3, "output_value": 0, "function_code": 5, "res": 0}]
+    elif device == "2" and operation == "start":
+        station_name = "remote_control"
+        command = [{"device_id": 1, "start_addr": 4, "output_value": 65280, "function_code": 5, "res": 65280}]
+    elif device == "2" and operation == "stop":
+        station_name = "remote_control"
+        command = [{"device_id": 1, "start_addr": 4, "output_value": 0, "function_code": 5, "res": 0}]
+
+    return station_name, command
+
+
+
+def save_log(file, message):
+    """
+    日志存储
+    @param message:
+    @return:
+    """
+    month = datetime.now().strftime('%Y%m')
+    path = f"./gateway-Log/{file}_{month}.txt"
+
+    print_log = open(path, 'a+')
+    # print(message)
+    message = f"{datetime.now()} {message}"
+    print(message, file=print_log)
+    print_log.close()
+
+
+
+if __name__ == "__main__":
+
+    historicalDataStorage = HistoricalDataStorage(read_write=0)
+    threading.Thread(target=historicalDataStorage.run, daemon=True, name='historicalDataStorage').start()
+
+    # 投饵建议
+    threading.Thread(target=FeedingStatistics().run, daemon=True, name=FeedingStatistics).start()
+
+    # 自动投喂
+    threading.Thread(target=AutoFeeding().run, daemon=True, name=AutoFeeding).start()
+
+    # 配电板的相关维保信息(使用功率、运行时间等)
+    threading.Thread(target=UpdateMaintenanceInfo().update_info, daemon=True, name=UpdateMaintenanceInfo()).start()
+
+    # # 电池电量低时,自启发电机
+    # threading.Thread(target=AutoCharge().run, daemon=True, name=AutoCharge).start()
+
+    # 根据存储的报警信息来控制蜂鸣器
+    threading.Thread(target=AlarmBuzzer().run, daemon=True, name=AlarmBuzzer).start()
+    
+    # 判断实时值是否异常,并记录
+    threading.Thread(target=AlarmRecord().run, daemon=True, name=AlarmRecord).start()
+    
+    # 自动控制聚鱼灯
+    threading.Thread(target=AutoSwitchJuyudeng().run, daemon=True, name=AutoSwitchJuyudeng).start()
+    
+    # 自动控制水下云台灯
+    threading.Thread(target=AutoSwitchYuntaideng().run, daemon=True, name=AutoSwitchYuntaideng).start()
+
+    # # 根据当前流速自动开关1501的PLC剖面功能
+    # threading.Thread(target=AutoProfile1501().run, daemon=True, name=AutoProfile1501).start()
+
+    # 远程开关量模块的复位逻辑
+    threading.Thread(target=ResetRemoteControl().run, daemon=True, name=ResetRemoteControl).start()
+
+
+    # 实时更新拉力计的计算参数,存入redis
+    threading.Thread(target=GetLalijiParam().run, daemon=True, name=GetLalijiParam).start()
+
+
+    app.run(host="0.0.0.0", port=18080, workers=1)

+ 89 - 0
005_H570/jikong_script/gateway_read_conn.py

@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*-
+"""
+@desc: 连接器:只读
+"""
+
+import time
+import threading
+from sanic import Sanic
+from sanic_cors import CORS, cross_origin
+from sanic import response
+from event_storage import EventStorage
+from utility import Utility
+from historical_data_storage import HistoricalDataStorage
+from feeding_statistics import FeedingStatistics
+from auto_feeding import AutoFeeding
+from auto_charge import AutoCharge
+from alarm import Alarm
+from api_context import ApiContext
+from update_maintenance_info import UpdateMaintenanceInfo
+from auto_switch_device import AutoSwitchDevice
+from alarm_buzzer import AlarmBuzzer
+from alarm_record import AlarmRecord
+from auto_switch_juyudeng import AutoSwitchJuyudeng
+from auto_switch_yuntaideng import AutoSwitchYuntaideng
+
+app = Sanic(__name__)
+CORS(app)
+
+
+gateway_storage = EventStorage()
+connector_config = gateway_storage.get_connector_config(read_write=1)
+Utility.start_connectors(connector_config)
+
+
+@app.route('/readRealText', methods=['POST'])
+async def read_point_data_text(request):
+    list = request.json['pointList']
+    dict = gateway_storage.get_real_data(list)
+    point_list = gateway_storage.get_point_info(list)
+    data_list = {}
+    for info in point_list:
+        data_list[info['io_point_name']] = str(dict["c"+str(info['serial_number'])]) + " " +str(info['unit'])
+    return response.json(data_list)
+
+@app.route('/readReal', methods=['POST'])
+async def read_point_data(request):
+    list = request.json['pointList']
+    dict = gateway_storage.get_real_data(list)
+    '''
+    data_list = gateway_storage.get_point_info(list)
+    for info in data_list:
+        info['value'] = dict["c"+str(info['serial_number'])]
+    '''
+    return response.json(dict)
+
+
+@app.route('/api', methods=['POST'])
+async def read_statistics_data(request):
+    if len(request.json) > 0:
+        list = []
+        for index in range(len(request.json)):
+            api_object = request.json[index]['apiObject']
+            parameter = request.json[index]['parameter']
+            api = ApiContext()
+            api.set_api_object(api_object)
+            result = api.operation(parameter)
+            list.append(result)
+        data_json = Utility.data_encoder(list)
+        return response.text(data_json)
+
+@app.route('/write',methods=['POST'])
+async def write_data(request):
+    t1 = time.time()
+    station_name = request.json["station_name"]
+    command = request.json["command"]
+    try:
+        result = Utility.available_connectors[station_name].send_command(command)
+        return response.json({'message': result})
+    except Exception as e:
+        print(station_name+"write[ERROR]:" + str(e))
+        return response.json({'message': result})
+
+
+if __name__ == "__main__":
+    historicalDataStorage = HistoricalDataStorage(read_write=1)
+    threading.Thread(target=historicalDataStorage.run, daemon=True, name='historicalDataStorage').start()
+
+    app.run(host="0.0.0.0", port=28080, workers=1)

+ 80 - 0
005_H570/jikong_script/gateway_web.py

@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*-
+
+from sanic import Sanic
+from sanic_cors import CORS, cross_origin
+from sanic import response
+from event_storage import EventStorage
+from utility import Utility
+from api_context import ApiContext
+
+
+app = Sanic(__name__)
+CORS(app)
+
+
+gateway_storage = EventStorage()
+
+@app.route('/readRealText', methods=['POST'])
+async def read_point_data_text(request):
+    list = request.json['pointList']
+    dict = gateway_storage.get_real_data(list)
+    point_list = gateway_storage.get_point_info(list)
+    data_list = {}
+    for info in point_list:
+        data_list[info['io_point_name']] = str(dict["c"+str(info['serial_number'])]) + " " +str(info['unit'])
+    return response.json(data_list)
+
+@app.route('/readReal', methods=['POST'])
+async def read_point_data(request):
+    list = request.json['pointList']
+    dict = gateway_storage.get_real_data(list)
+    '''
+    data_list = gateway_storage.get_point_info(list)
+    for info in data_list:
+        info['value'] = dict["c"+str(info['serial_number'])]
+    '''
+    return response.json(dict)
+
+
+@app.route('/api', methods=['POST'])
+async def read_statistics_data(request):
+    if len(request.json) > 0:
+        list = []
+        for index in range(len(request.json)):
+            api_object = request.json[index]['apiObject']
+            parameter = request.json[index]['parameter']
+            api = ApiContext()
+            api.set_api_object(api_object)
+            result = api.operation(parameter)
+            list.append(result)
+        data_json = Utility.data_encoder(list)
+        return response.text(data_json)
+
+@app.route('/write',methods=['POST'])
+async def write_data(request):
+    station_name = request.json["station_name"]
+    command = request.json["command"]
+    try:
+        result = Utility.available_connectors[station_name].send_command(command)
+        return response.json({'message': result})
+    except Exception as e:
+        print(station_name+"write[ERROR]:" + str(e))
+        return response.json({'message': result})
+
+
+
+@app.route('/s7/getState', methods=['POST'])
+async def read_point_data(request):
+    point_list = ["c577", "c578", "c569", "c570", "c571", "c572", "c573", "c574", "c575",
+                  "c402", "c423", "c411", "c815", "c432", "c817"]
+    dict = gateway_storage.get_real_data(point_list)
+
+    return response.json(dict)
+
+
+
+
+
+if __name__ == "__main__":
+    app.run(host="0.0.0.0", port=8080, workers=8)

+ 48 - 0
005_H570/jikong_script/get_laliji_param.py

@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+@CreateTime: 2023/02/01 09:50
+@Author: lxc
+@LastEditTime: 
+@Desctiption: 实时获取拉力计 计算公式的参数,并存入redis中
+"""
+
+from event_storage import EventStorage
+from log import OutPutLog
+import time
+from datetime import datetime
+
+class GetLalijiParam:
+    def __init__(self):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+
+    def run(self):
+        self._log.info("[GetLalijiParam] - GetLalijiParam module is running!")
+
+        # 拉力计1-6原始数据
+        serial_list = ['c869', 'c870', 'c871', 'c872', 'c873', 'c874']
+        run_time = 0
+        while True:
+            this_time = time.time()
+            if this_time - run_time > 5:
+                run_time = this_time
+
+                real_data_dict = self._storage.get_real_data(serial_list)
+                status = False
+                for v in real_data_dict.values():
+                    if v is not None:
+                        status = True
+
+                if status:
+                    self.save_param()
+
+    def save_param(self):
+        """实时获取拉力计 计算公式的参数,并存入redis中"""
+        get_param_sql = "SELECT `serial_number`,`value` FROM `laliji_config`;"
+        param_res = self._storage.execute_sql(get_param_sql)
+        param_dict = {}
+        for each in param_res:
+            param_dict[each['serial_number']] = each['value']
+        self._storage.real_time_data_storage(param_dict)
+

+ 291 - 0
005_H570/jikong_script/hard_disk_storage.py

@@ -0,0 +1,291 @@
+import pymysql
+import traceback
+import time
+import datetime
+from log import OutPutLog
+
+class HardDiskStorage():
+    def __init__(self, config, port=3306, charset='utf8'):
+        self._log = OutPutLog()
+        self.host = config['ip']
+        self.user = config['username']
+        self.passwd = config['password']
+        self.db = config['dataBaseName']
+        self.port = port
+        self.charset = charset
+        self.conn = None
+        self._conn()
+
+    def _conn(self):
+        try:
+            self.conn = pymysql.connect(host=self.host, user=self.user, password=self.passwd, database=self.db, port=self.port, autocommit=True)
+            return True
+        except:
+            self._log.error(traceback.format_exc())
+            return False
+
+    def _reConn(self, num=28800, stime=3):  # 重试连接总次数为1天,这里根据实际情况自己设置,如果服务器宕机1天都没发现就......
+        _number = 0
+        _status = True
+        while _status and _number <= num:
+            try:
+                self.conn.ping()  # cping 校验连接是否异常
+                _status = False
+            except Exception as e:
+                self._log.error(e)
+                if self._conn() == True:  # 重新连接,成功退出
+                    print('haha')
+                    _status = False
+                    break
+                _number += 1
+                time.sleep(stime)  # 连接不成功,休眠3秒钟,继续循环,知道成功或重试次数结束
+
+    def get_station_info(self, station_name):
+        sql = "SELECT * FROM data_point_tbl where station_name = '%s'" % (station_name)
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            self._log.error(traceback.format_exc())
+            return False
+
+    def get_point_info(self, point_tuple):
+        if point_tuple:
+            sql = "SELECT * FROM data_point_tbl where serial_number in %s" % (str(point_tuple))
+        else:
+            sql = "SELECT * FROM data_point_tbl"
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            self._log.error(traceback.format_exc())
+            return False
+
+    def get_table_data(self, select_info):
+        table_name = "table_" + select_info['deviceName']
+        time_begin = select_info['timeBegin']
+        time_end = select_info['timeEnd']
+        column = select_info['pointList']
+        if len(column) > 0:
+            sql = "SELECT times"
+            for column_name in column:
+                sql = sql + "," + column_name
+            sql = sql + " FROM %s WHERE times > '%s' AND times < '%s'" % (table_name, time_begin, time_end)
+        else:
+            sql = "SELECT * FROM %s WHERE times > '%s' AND times < '%s';" % (table_name, time_begin, time_end)
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            self._log.error(traceback.format_exc())
+            return None
+
+    def get_connectors(self, read_write):
+        sql = f"SELECT * FROM station_info_tbl WHERE status = 1 AND `read_write`={read_write};"
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            self._log.error(traceback.format_exc())
+            return None
+
+    # def create_delete_stale_data_event(self, eventName, table_name, day):
+    #     self.cursor = self.conn.cursor()
+    #     sql = "create event %s on SCHEDULE every 1 day do delete from %s where times<(CURRENT_TIMESTAMP() + INTERVAL -%s DAY);" % (
+    #         eventName, table_name, day)
+    #     self.cursor.execute(sql)
+    #     self.cursor.close()
+    #
+    # def create_many_column_table(self, table_name, list):
+    #     self.cursor = self.conn.cursor()
+    #     for index in range(len(list)):
+    #         dataType = list[index]['storageType']
+    #         columnName = "c" + str(list[index]['serialNumber'])
+    #         sql_c = "CREATE TABLE IF NOT EXISTS %s (times datetime NOT NULL,INDEX (times)) \
+    #             ENGINE=InnoDB DEFAULT CHARSET=utf8;" % (table_name)
+    #         sql_add = "ALTER TABLE %s ADD %s %s " % (table_name, columnName, dataType)
+    #         try:
+    #             self.cursor.execute(sql_c)
+    #             self.cursor.execute(sql_add)
+    #         except:
+    #             self._log.error(traceback.format_exc())
+    #     sql_send = "ALTER TABLE %s ADD 'is_send'tinyint NOT NULL DEFAULT '0'" % (table_name)
+    #     self.cursor.execute(sql_send)
+    #     self.cursor.close()
+
+    def insert_column_many(self, table_name, timeNow, dict):
+        try:
+            self.cursor = self.conn.cursor()
+            sql = "INSERT INTO `%s` (times" % (table_name)
+            for key_name in dict.keys():
+                sql = sql + "," + key_name
+            sql = sql + ") VALUE ('" + str(timeNow) + "'"
+            for key_name in dict.keys():
+                # data = "," + str(dict[key_name])
+                if table_name.endswith("_original"):
+                    data = ",\'" + str(dict[key_name]) + "\'"
+                else:
+                    data = "," + str(dict[key_name])
+                sql = sql + data
+            sql = sql + ")"
+            try:
+                self.cursor.execute(sql)
+                # 提交到数据库执行
+                self.conn.commit()
+            except Exception as e:
+                # 如果发生错误则回滚
+                self.conn.rollback()
+                self._log.error(e)
+        except Exception as e:
+            self._reConn()
+            self._log.error(e)
+        else:
+            self.cursor.close()
+
+    def close(self):
+        self.conn.close()
+
+    def get_command_info(self, station_name):
+        sql = "SELECT command FROM command where station_name = %s" % ("'" + station_name + "'")
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            self._log.error(traceback.format_exc())
+            return None
+
+    # lee
+    def get_device_name_by_station_name(self, station_name):
+        sql = "SELECT DISTINCT device_name FROM data_point_tbl WHERE station_name = '%s' " % station_name
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            print(traceback.format_exc())
+            return None
+
+    def get_data_point_by_device_name(self, device_name):
+        sql = "SELECT * FROM data_point_tbl WHERE device_name = '%s' AND hard_storage=1;" % device_name
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            print(traceback.format_exc())
+            return None
+
+    # ----------------------------------------------------------------------------------------------
+    def execute_sql(self, sql):
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            print("execute_sql"+str(traceback.format_exc()))
+            self._log.error("execute_sql"+str(traceback.format_exc()))
+            return None
+
+    def get_table_name(self):
+        '''[{'device_name': 'zfdj_electric'}, {'device_name': 'jbd1_electric'}, {'device_name': 'yysbdlfdx_electric'}, ...]'''
+        sql = "SELECT DISTINCT device_name FROM data_point_tbl;"
+        res = self.execute_sql(sql)
+
+        return res
+
+    # def table_xxx_insert_data(self, format_data_dict, tables_name, save_time):
+    #     try:
+    #         for table in tables_name:
+    #             table_name = "table_" + table['device_name']  # zfdj_electric
+    #             sql_columm = "SHOW FIELDS FROM %s WHERE Field like \'c%%\';" % (table_name)
+    #             columns = []  # ['c1', 'c2',...,'c10', 'times', 'is_send']
+    #             value = []  # [1.401298464324817e-45, 0.0,...,1.401298464324817e-45, 'NOW()', 0]
+    #             for each in self.execute_sql(sql_columm):
+    #                 columns.append(each['Field'])
+    #                 value.append(format_data_dict[each['Field']])
+    #             columns.append('times')
+    #             value.append(save_time)
+    #             columns.append('is_send')
+    #             value.append(0)
+    #             sql_insert = "INSERT INTO %s %s VALUES %s;" % (table_name, format(tuple(columns)).replace('\'', ''), format(tuple(value)))
+    #             print(sql_insert)
+    #             # self.execute_sql(sql_insert)
+    #     except:
+    #         self._log.error(traceback.format_exc())
+
+
+
+    def get_device_info(self, device_name):
+        sql = "SELECT * FROM data_point_tbl where device_name = '%s'" % (device_name)
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            results = self.cursor.fetchall()
+            self.cursor.close()
+            return results
+        except:
+            self._log.error(traceback.format_exc())
+            return False
+
+
+    def execute_update_sql(self, sql):
+        """执行UPDATE、INSERT、DELETE语句"""
+        try:
+            self._reConn()
+            self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
+            self.cursor.execute(sql)
+            self.conn.commit()
+            self.cursor.close()
+            return True
+        except pymysql.Error as mysql_error:
+            self._log.error(f"MYSQL执行失败!{sql}")
+            self._log.error(mysql_error)
+            return False
+
+
+    def gather_fish_light_info(self, location):
+        """水下聚鱼灯远程控制功能:查找指定位置的聚鱼灯的相关控制信息"""
+        sql = f"SELECT control_mode,status,definite_time FROM `gather_fish_light_control` WHERE location=\'{location}\';"
+
+        data = self.execute_sql(sql)
+        return data
+
+    def get_gather_fish_light_command(self):
+        """水下聚鱼灯远程控制功能:查看控制聚鱼灯的指令"""
+        sql = "SELECT control_mode,status,command FROM gather_fish_light_command;"
+        data = self.execute_sql(sql)
+
+        return data
+
+
+

+ 81 - 0
005_H570/jikong_script/historical_data_storage.py

@@ -0,0 +1,81 @@
+"""
+@Date  :2021/5/24/10:20
+@Desc  :
+"""
+
+
+
+import json
+import threading
+
+from event_storage import EventStorage
+import time
+from log import OutPutLog
+
+
+class HistoricalDataStorage:
+    def __init__(self, read_write):
+        self._storage = EventStorage()
+        self._log = OutPutLog()
+        self._read_write = read_write
+
+
+    # 历史存储主函数
+    def run(self):
+        self._log.info('[HistoricalDataStorage] - Historical data storage module is running!')
+        station_info = self._storage.hardDiskStorage.get_connectors(self._read_write)  # 获取所有站点信息
+        all_devices = []
+        for item in station_info:
+            station_name = item['station_name']  # 站点名称
+            connector_config = json.loads(item['connector_config'])     # 加载json格式connector_config参数
+            save_frequency = connector_config['save_frequency']         # 获取存储频率
+            devices_each_station = self._storage.hardDiskStorage.get_device_name_by_station_name(station_name)  # 根据站点名称获取设备列表
+
+            for i in devices_each_station:
+                temp_dict = {}
+
+                # 获取每个设备所有点的serial_number,转换为键列表
+                device_name = i['device_name']
+                data_point_each_device = self._storage.hardDiskStorage.get_data_point_by_device_name(
+                    device_name)  # 根据设备名称获取设备点表
+
+                serial_number_list = []
+                for items in data_point_each_device:
+                    serial_number = 'c' + str(items['serial_number'])
+                    serial_number_list.append(serial_number)
+
+                temp_dict['device_name'] = device_name
+                temp_dict['save_frequency'] = save_frequency
+                temp_dict['serial_number_list'] = serial_number_list
+                temp_dict['last_save_time'] = 0
+                all_devices.append(temp_dict)
+
+        while 1:
+            time.sleep(0.2)
+            for item in all_devices:
+                save_frequency = item['save_frequency']
+                last_save_time = item['last_save_time']
+                now_time = time.time()
+                if now_time - last_save_time >= save_frequency:
+                    item['last_save_time'] = now_time
+                    save_time = int(now_time) - int(now_time) % save_frequency
+                    save_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(save_time))
+
+                    serial_number_list = item['serial_number_list']
+                    real_time_data = self._storage.memoryStorage.get_value(serial_number_list)  # 根据键列表查询实时数据库
+                    flag = False  # 是否允许存储标志位
+                    for key in real_time_data:
+                        # 值全部为空,不允许存储
+                        if real_time_data[key]:
+                            flag = True
+                            break
+                    if flag and len(serial_number_list) >= 1:
+                        for key in real_time_data:  # redis值为None的
+                            if real_time_data[key] is None:  # redis数据库未存储此值
+                                real_time_data[key] = 'null'
+                            if real_time_data[key] == '':  # redis存储的为空值
+                                real_time_data[key] = 'null'
+                        table_name = "table_" + str(item['device_name'])  # 根据站名计算表名
+                        # self._log.debug("[HistoricalDataStorage] - " + repr(table_name) + '<-' + repr(real_time_data))
+                        self._storage.hardDiskStorage.insert_column_many(table_name, save_time, real_time_data)
+                        #self._log.info(repr(table_name) + '<-' + repr(real_time_data))

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است