josefkyrian

goodwe data sender

May 20th, 2022 (edited)
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.30 KB | None | 0 0
  1. #!/usr/bin/python3
  2.  
  3. # pip3 install goodwe==0.3.1
  4.  
  5.  
  6. import asyncio
  7. import goodwe
  8. import goodwe.sensor
  9. import logging
  10. import sys
  11. import time
  12. from optparse import OptionParser
  13. import aiohttp
  14. import datetime
  15. import json
  16. import importlib.metadata
  17. import time
  18.  
  19. if False:
  20.     import packaging.version
  21.  
  22.     if (packaging.version.parse(importlib.metadata.version('goodwe')) <= packaging.version.parse('0.3')):
  23.         for i in range(1, 6):
  24.             print("You should upgrade your goodwe library" + ("!" * i))
  25.             time.sleep(1)
  26.         #endif
  27.     #endif
  28. #endif
  29.  
  30.  
  31. root = logging.getLogger()
  32. root.setLevel(logging.DEBUG)
  33.  
  34. handler = logging.StreamHandler(sys.stdout)
  35. handler.setLevel(logging.INFO)
  36. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  37. handler.setFormatter(formatter)
  38. root.addHandler(handler)
  39.  
  40.  
  41. parser = OptionParser(usage = '%prog [options]')
  42. parser.add_option("", "--inverter-host", dest="inverter_host", help="Goodwe Inverter Address")
  43. parser.add_option("", "--inverter-id", dest="inverter_id", help="Id of inverter")
  44. parser.add_option("", "--http-post-url", dest="http_post_url", help="HTTP post url")
  45. parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Verbose logging")
  46. (options, args) = parser.parse_args()
  47.  
  48. if (not all([options.inverter_host, options.http_post_url])):
  49.     print("Not all options given", file = sys.stderr)
  50.     parser.print_help()
  51.     sys.exit(-1)
  52. #endif
  53.    
  54. if (options.verbose):
  55.     handler.setLevel(logging.DEBUG)
  56. #endif
  57.  
  58.  
  59. def getDBColumnFromSensor(sensor):
  60.     if (sensor.id_ == 'grid_mode'):
  61.         sensor.kind = goodwe.inverter.SensorKind.GRID
  62.     elif (sensor.id_ == 'grid_mode_label'):
  63.         sensor.kind = goodwe.inverter.SensorKind.GRID
  64.     elif (sensor.id_ == 'temperature_air'):
  65.         sensor.kind = None
  66.     elif (sensor.id_ == 'temperature_module'):
  67.         sensor.kind = None
  68.     elif (sensor.id_ == 'temperature'):
  69.         sensor.kind = None
  70.     elif (sensor.id_ == 'safety_country'):
  71.         sensor.kind = None
  72.     elif (sensor.id_ == 'safety_country_label'):
  73.         sensor.kind = None
  74.     elif (sensor.id_ == 'vgrid'):
  75.         sensor.id_ = 'vgrid1'
  76.     elif (sensor.id_ == 'igrid'):
  77.         sensor.id_ = 'igrid1'
  78.     elif (sensor.id_ == 'fgrid'):
  79.         sensor.id_ = 'fgrid1'
  80.     elif (sensor.id_ == 'pgrid'):
  81.         sensor.id_ = 'pgrid1'
  82.     #endif
  83.  
  84.     dbType = None
  85.     if (isinstance(sensor, goodwe.sensor.Long)):
  86.         dbType = 'int'
  87.     elif (isinstance(sensor, goodwe.sensor.Integer)):
  88.         dbType = 'int'
  89.     elif (isinstance(sensor, goodwe.sensor.Timestamp)):
  90.         dbType = 'datetime'
  91.     elif (isinstance(sensor, goodwe.sensor.Voltage)):
  92.         dbType = 'double'
  93.     elif (isinstance(sensor, goodwe.sensor.Current)):
  94.         dbType = 'double'
  95.     elif (isinstance(sensor, goodwe.sensor.Power4)):
  96.         dbType = 'double'
  97.     elif (isinstance(sensor, goodwe.sensor.Power)):
  98.         dbType = 'double'
  99.     elif (isinstance(sensor, goodwe.sensor.Energy4)):
  100.         dbType = 'double'
  101.     elif (isinstance(sensor, goodwe.sensor.Energy)):
  102.         dbType = 'double'
  103.     elif (isinstance(sensor, goodwe.sensor.Frequency)):
  104.         dbType = 'double'
  105.     elif (isinstance(sensor, goodwe.sensor.Temp)):
  106.         dbType = 'double'
  107.     elif (isinstance(sensor, goodwe.sensor.Decimal)):
  108.         dbType = 'double'
  109.     elif (isinstance(sensor, goodwe.sensor.Float)):
  110.         dbType = 'double'
  111.     elif (isinstance(sensor, goodwe.sensor.Calculated)):
  112.         if (sensor.id_ == 'ppv'):
  113.             dbType = 'int'
  114.         elif (sensor.id_ == 'grid_in_out'):
  115.             dbType = 'int'
  116.         elif (sensor.id_ == 'grid_in_out_label'):
  117.             dbType = 'text'
  118.         elif (sensor.id_ == 'pbattery1'):
  119.             dbType = 'int'
  120.         elif (sensor.id_ == 'errors'):
  121.             dbType = 'text'
  122.         elif (sensor.id_ == 'diagnose_result_label'):
  123.             dbType = 'text'
  124.         elif (sensor.id_ == 'house_consumption'):
  125.             dbType = 'int'
  126.         elif (sensor.id_ == 'battery_error'):
  127.             dbType = 'text'
  128.         elif (sensor.id_ == 'battery_warning'):
  129.             dbType = 'text'
  130.         #endif
  131.     elif (isinstance(sensor, goodwe.sensor.Enum2)):
  132.         dbType = 'text'
  133.     elif (isinstance(sensor, goodwe.sensor.Enum)):
  134.         dbType = 'text'
  135.     elif (isinstance(sensor, goodwe.sensor.Byte)):
  136.         dbType = 'int'
  137.     elif (isinstance(sensor, goodwe.sensor.EnumCalculated)):
  138.         dbType = 'text'
  139.     elif (hasattr(goodwe.sensor, 'EnumL') and isinstance(sensor, goodwe.sensor.EnumL)):
  140.         dbType = 'text'
  141.     elif (hasattr(goodwe.sensor, 'EnumH') and isinstance(sensor, goodwe.sensor.EnumH)):
  142.         dbType = 'text'
  143.     elif (hasattr(goodwe.sensor, 'EnumBitmap4') and isinstance(sensor, goodwe.sensor.EnumBitmap4)):
  144.         dbType = 'text'
  145.     elif (hasattr(goodwe.sensor, 'EnumBitmap22') and isinstance(sensor, goodwe.sensor.EnumBitmap22)):
  146.         dbType = 'text'
  147.     elif (hasattr(goodwe.sensor, 'Reactive') and isinstance(sensor, goodwe.sensor.Reactive)):
  148.         dbType = 'int'
  149.     elif (hasattr(goodwe.sensor, 'Reactive4') and isinstance(sensor, goodwe.sensor.Reactive4)):
  150.         dbType = 'int'
  151.     elif (hasattr(goodwe.sensor, 'Apparent') and isinstance(sensor, goodwe.sensor.Apparent)):
  152.         dbType = 'int'
  153.     elif (hasattr(goodwe.sensor, 'Apparent4') and isinstance(sensor, goodwe.sensor.Apparent4)):
  154.         dbType = 'int'
  155.     elif (hasattr(goodwe.sensor, 'CellVoltage') and isinstance(sensor, goodwe.sensor.CellVoltage)):
  156.         dbType = 'double'
  157.     #endif
  158.  
  159.     if (dbType == None):
  160.         print('Unknown sensor db type', sensor)
  161.         return None
  162.     #endif
  163.  
  164.     columnName = sensor.id_
  165.     columnNamePrefix = None
  166.  
  167.     if (sensor.kind == goodwe.inverter.SensorKind.PV):
  168.         columnNamePrefix = 'pv'
  169.     elif (sensor.kind == goodwe.inverter.SensorKind.AC):
  170.         columnNamePrefix = 'ac'
  171.     elif (sensor.kind == goodwe.inverter.SensorKind.UPS):
  172.         columnNamePrefix = 'backup'
  173.     elif (sensor.kind == goodwe.inverter.SensorKind.BAT):
  174.         columnNamePrefix = 'battery'
  175.     elif (sensor.kind == goodwe.inverter.SensorKind.GRID):
  176.         columnNamePrefix = 'grid'
  177.     elif (sensor.kind == None):
  178.         columnNamePrefix = ''
  179.     #endif
  180.  
  181.     if (columnNamePrefix == None):
  182.         print('Unknown sensor kind type', sensor)
  183.         return None
  184.     #endif
  185.  
  186.     if (not columnName.startswith(columnNamePrefix) and columnNamePrefix != ''):
  187.         columnName = '%s_%s' % (columnNamePrefix, columnName)
  188.     #endif
  189.    
  190.  
  191.     return {
  192.         'name': columnName,
  193.         'type': dbType,
  194.         'comment': sensor.name + (' (%s)' % sensor.unit if sensor.unit else ''),
  195.         'kind': columnNamePrefix,
  196.     }
  197. #enddef
  198.  
  199.  
  200. async def get_runtime_data(options):
  201.     inverter = goodwe.ET(options.inverter_host, 0, timeout = 1, retries = 0)
  202.     await inverter.read_device_info()
  203.  
  204.     print("Connected to inverter %s, S/N:%s." % (inverter.model_name, inverter.serial_number))
  205.  
  206.     debugColumns = False
  207.  
  208.     while True:
  209.         try:
  210.             runtime_data = await inverter.read_runtime_data()
  211.         except Exception as e:
  212.             logging.info('ERRRRRRRRRRRRRRRRRRR! %s' % e)
  213.             print(e)
  214.             # pockat 10s v pripade chyby, protoze treba komunikuje s menicem
  215.             # neco jineho napr. SolarGo, tak abychom mu umoznili, taky se liznout
  216.             await asyncio.sleep(10)
  217.             continue
  218.         #endtry
  219.         #time.sleep(0.1)
  220.         #continue
  221.  
  222.         logging.info('Got data')
  223.  
  224.         columnValues = {
  225.             'pv_inverter_id' : int(options.inverter_id),
  226.         }
  227.         for sensor in inverter.sensors():
  228.             if sensor.id_ in runtime_data:
  229.                 value = runtime_data[sensor.id_]
  230.                 if ((sensor.id_.endswith('_h') or sensor.id_.endswith('_l')) and value < 0):
  231.                     value = 65536 + value
  232.                 #endif
  233.                 column = getDBColumnFromSensor(sensor)
  234.                 columnValues[column['name']] = value
  235.                 if (debugColumns):
  236.                     print(sensor.id_ + ':')
  237.                     print('    value:', value)
  238.                     print('    sensor:', sensor)
  239.                     print('    column:', column)
  240.                 #endif
  241.             #endif
  242.                    
  243.             if (debugColumns):
  244.                 print('---')
  245.             #endif
  246.         #endfor
  247.        
  248.         if (debugColumns):
  249.             sys.exit()
  250.         #endif
  251.  
  252.         for k, v in columnValues.items():
  253.             if (isinstance(v, datetime.datetime)):
  254.                 columnValues[k] = v.strftime('%Y-%m-%d %H:%M:%S')
  255.             #endif
  256.         #endfor
  257.  
  258.         logging.info('Post data...')
  259.         logging.debug(json.dumps(columnValues, ensure_ascii=False, indent=4, sort_keys=True))
  260.  
  261.         while True:
  262.             try:
  263.                 async with aiohttp.ClientSession() as session:
  264.                     logging.info('Do post...')
  265.                     async with session.post(options.http_post_url, json = columnValues, timeout = 10) as response:
  266.                         logging.info('Got response %s', await response.text())
  267.                         res = await response.json()
  268.                         if (res['status'] == 200):
  269.                             break
  270.                         #endif
  271.                     #endwith
  272.                 #endwith
  273.             except Exception as e:
  274.                 print('Error: %s' % repr(e))
  275.             #endtry
  276.  
  277.             time.sleep(1)
  278.         #endwhile
  279.  
  280.         time.sleep(1)
  281.     #endwhile
  282. #enddef
  283.  
  284.  
  285. asyncio.run(get_runtime_data(options))
  286.  
Advertisement
Add Comment
Please, Sign In to add comment