zondag 6 december 2015

Smart Meter Dashboard (1) - Uitlezen Chint Omvormer

Samen met een vriend zijn we een eigen (verbeterde) versie aan het maken van het Smart Meter Dashboard.
Hij is bezig met de Web-pagina's en ik hou me bezig met de Python scripts om de data te verzamelen.

Ik ben de afgelopen weken bezig geweest met het uitkunnen lezen van de Chint-Omvormer van mijn Zonnepanelen.
Hiervoor heb ik op internet een Python library gevonden, namelijk pv - Python-based PV Inverter Monitoring Library.

In het bestand cms.py heb ik echter een regel toegevoegd omdat ik deze miste in de output:
Orgineel

                        'Ipv3':         ('\x06',                10.0),          # PV3 Current (A)
                        'Vpv':          ('\x40',                10.0),          # PV Voltage (V)
Aangepast:
                        'Ipv3':         ('\x06',                10.0),          # PV3 Current (A)
                        'E-Today':      ('\x0D',                100.0),         # Energy to grid Today (kWh)
                        'Vpv':          ('\x40',                10.0),          # PV Voltage (V)


Ik heb dit script geplaatst op een Raspberry Pi, uitgerust met de nieuwste versie van Raspbian (Jessie), die met een USB-Serieel-kabel is aangesloten op de RS-232 poort van de omvormer.

Daarnaast heb ik een script gemaakt dat gebruik maakt van de library en gekozen data in een MySQL database plaatst.
Het script dat ik heb gemaakt is het volgende:

MySQL_Loaded=True
import sys
import datetime
import threading
import pv
import serial
#from datetime import datetime, time
from pv import cms
try:
  import mysql.connector
except ImportError:
  MySQL_Loaded=False

p1_mysql_user = 'MySQL_SMD_Gebruiker'
p1_mysql_passwd = 'MySQL_SMD_Gebruiker_wachtwoord'
p1_mysql_host = 'localhost'
p1_mysql_db = 'SMD'

def show_error():
  ft = sys.exc_info()[0]
  fv = sys.exc_info()[1]
  print("Fout type: %s" % ft)
  print("Fout waarde: %s" % fv)
  return

def db_pv_telegram():
  query = "insert into pv_log values (\'" + \
    pv_timestamp + "\',\'" + \
    pv_meter_supplier + "\',\'" + \
    pv_header + "\',\'" + \
    str(pv_equipment_id) + "\',\'" + \
    str(pv_voltage) + "\',\'" + \
    str(pv_current_power_out) + "\',\'" + \
    str(pv_current_current_out) + "\',\'" + \
    str(pv_today_power_out) + "\',\'" + \
    str(pv_meterreading_out) + "\',\'" + \
    str(pv_hours) + "\',\'" + \
    str(pv_temp) + "\',\'" + \
    str(pv_mode) + "\',\'" + \
    str(pv_error) + "\')"

#  print (query)
  try:
    db = mysql.connector.connect(user=p1_mysql_user, password=p1_mysql_passwd, host=p1_mysql_host, database=p1_mysql_db)
    c = db.cursor()
    c.execute(query)
    db.commit()
    print("PV telegram in database %s / %s gelogd op: %s" % (p1_mysql_host, p1_mysql_db, pv_timestamp) )
    db.close()
  except:
    show_error()
    print("Fout bij het openen van / schrijven naar database %s / %s. Log kwijt." % (p1_mysql_host, p1_mysql_db) )
  return

#pv.debug()
#pv.debug_color()

port = serial.Serial('/dev/ttyUSB0', timeout=5)
inv = cms.Inverter(port)

def printit():
#  print(datetime.datetime.now())
  global pv_timestamp, pv_meter_supplier, pv_header, pv_equipment_id, pv_voltage, pv_current_power_out, pv_current_current_out, pv_today_power_out
  global pv_yesterday_power_out, pv_meterreading_out, pv_hours, pv_temp, pv_mode, pv_error, pv_previous_power_out

  try:
    if pv_meter_supplier in globals():
      pv_timestamp = datetime.datetime.strftime(datetime.datetime.today(), "%Y-%m-%d %H:%M:%S" )
  except NameError:
    pv_timestamp = datetime.datetime.strftime(datetime.datetime.today(), "%Y-%m-%d %H:%M:%S" )
    pv_meter_supplier = '-'
    pv_header = '-'
    pv_equipment_id = 0
    pv_voltage = 0
    pv_current_power_out = 0
    pv_current_current_out = 0
    pv_today_power_out = 0
    pv_previous_power_out = 0
    pv_yesterday_power_out = 0
    pv_temp = 0
    pv_mode = 0
    pv_error = 0
    pv_meterreading_out = 0
    pv_hours = 0
    print ("===============================[ OPSTARTEN ]===============================")

  pv_timestamp = datetime.datetime.strftime(datetime.datetime.today(), "%Y-%m-%d %H:%M:%S" )

  print ("==========================[ %s ]==========================" % pv_timestamp )
  threading.Timer(10.0, printit).start()
  inv.reset()                    # Reset all communications on the serial connection
  sn = inv.discover()            # Look for connected devices
  if sn is None:
    print ("Inverter is not connected.")
    print ("pv_today_power_out     : %s" % pv_today_power_out)
    print ("pv_yesterday_power_out : %s" % pv_yesterday_power_out)
    pv_voltage = 0
    pv_current_power_out = 0
    pv_current_current_out = 0
    pv_temp = 0
    pv_mode = 0
    pv_error = 0
    now = datetime.datetime.now()
    now_time = now.time()
    if datetime.time(0,30) >= now_time >= datetime.time(0,0) and pv_yesterday_power_out == 0:
      pv_yesterday_power_out = pv_today_power_out
      pv_today_power_out = 0
    db_pv_telegram()
    return
  ok = inv.register(sn)        # Associates the inverter and assigns default address
  version =  (inv.version())
  splitted = version.split()
  count = 0
  while count <= len(splitted)-1:
    count = count + 1
  param_layout = inv.param_layout()
  parameters = inv.parameters(param_layout)
  status_layout = inv.status_layout()
  status = inv.status(status_layout)
  parameters = dict(parameters)
  status = dict(status)

  pv_meter_supplier = splitted[4]
  pv_header = version
  pv_equipment_id = splitted[5]
  pv_voltage = status['Vpv']
  pv_current_power_out = status['Pac']
  pv_current_current_out = status['Iac']
  pv_today_power_out = status['E-Today']
  pv_meterreading_out = status['E-Total']
  pv_hours = status['h-Total']
  pv_temp = status['Temp-inv']
  pv_mode = status['Mode']
  pv_error = status['Error']
  print ("[ Voor vergelijkingen: ]")
  print ("pv_today_power_out     : %s" % pv_today_power_out)
  print ("pv_previous_power_out  : %s" % pv_previous_power_out)
  print ("pv_yesterday_power_out : %s" % pv_yesterday_power_out)
  if (pv_today_power_out - pv_yesterday_power_out < 0) and (pv_today_power_out < pv_previous_power_out):
    pv_yesterday_power_out = 0
  else:
    pv_previous_power_out = pv_today_power_out
    pv_today_power_out = pv_today_power_out - pv_yesterday_power_out
  print ("[ Na vergelijkingen: ]")
  print ("pv_today_power_out     : %s" % pv_today_power_out)
  print ("pv_previous_power_out  : %s" % pv_previous_power_out)
  print ("pv_yesterday_power_out : %s" % pv_yesterday_power_out)
  db_pv_telegram()

  print ("==========================================================================================")
  return

printit()
Uiteraard zijn de database login gegevens geanonimiseerd.
In MySQL heb ik een database aangemaakt met de naam SMD, daarin heb ik een tabel aangemaakt met de naam: pv_log.
De code om de kolommen aan te maken is de volgende:
CREATE TABLE `pv_log` (
 `pv_timestamp` DATETIME NOT NULL,
 `pv_meter_supplier` TINYTEXT NULL,
 `pv_header` TINYTEXT NULL,
 `pv_equipment_id` TINYTEXT NULL,
 `pv_voltage` DECIMAL(6,3) NULL DEFAULT NULL,
 `pv_current_power_out` DECIMAL(10,3) NULL DEFAULT NULL,
 `pv_current_current_out` DECIMAL(6,3) NULL DEFAULT NULL,
 `pv_today_power_out` DECIMAL(6,3) NULL DEFAULT NULL,
 `pv_meterreading_out` DECIMAL(9,3) NULL DEFAULT NULL,
 `pv_hours` INT(11) NULL DEFAULT NULL,
 `pv_temp` DECIMAL(3,1) NULL DEFAULT NULL,
 `pv_mode` TINYINT(2) NULL DEFAULT NULL,
 `pv_error` TINYINT(3) NULL DEFAULT NULL
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=COMPACT
;

Tevens heb ik een gebruiker aangemaakt die de rechten heeft om gegevens naar de SMD/pv_log te schrijven en te lezen. op de Raspberry Pi heb ik python, python-mysql.connector en python-serial geïnstalleerd met behulp van apt-get.

De Chint omvormer, welke trouwens gemaakt wordt door PhoenixTec en ook onder andere merken verkrijgbaar is, heeft wat toevoegingen welke best lastig zijn voor je PV_Today.
Namelijk de volgende:
  1. Na opstarten tot de eerste 0,1 kWh is opgewekt, geeft de omvormer de eindstand van gisteren weer
  2. aan het eind van de dag "stuitert" de dag-opbrengst omdat de omvormer soms niet meer reageert (uitgeschakelt is) door te weinig zonlicht.
 Beide eigenaardigheden heb ik in mijn script kunnen ondervangen, en loopt de dagopbrengst (punt 2) door tot middernacht, waarna hij op 0 gezet wordt.

Het script dat ik dit blog beschrijf is nog een test-versie en ik zal in de komende tijd herschreven worden. Maar hopelijk hebben mensen die hun omvormer uit willen lezen er al wat aan.

zaterdag 15 augustus 2015

Voorstellen

Ik zal mij even voorstellen. Ik ben Raymond.
In deze blog wil ik mijn knutsel-projecten gaan verslaan.

Thinkering


Knutselen betekent in het Engels "tinkering", wat een stuk beter klinkt in mijn oren, knutselen klinkt mij te simpel, thinkering klinkt meer als iets waar je over na hebt gedacht.

Hierbij ook nog even de vertaling zoals ik die vond op het internet:
  1. tinkering:
    • knutselen ; knutselwerk ; geknutsel ; knutselarij ; gebroddel ; geklungel
  2. tinker:
    • knutselen ; sleutelen ; fröbelen ; prutsen ; verwarren ; haspelen ; tot een warboel maken ; verprutsen ; aanmodderen ; rommelen 
Verwarren, tot een warboel maken, verprutsen, aanmodderen, zijn nou toch niet echt woorden waar ik mijn projecten mee wil omschrijven (althans dat is mijn bedoeling).

Projecten


Mijn projecten hebben voornamelijk tot doel het dagelijks leven te veraangenamen.

Projecten die ik in het verleden al heb gemaakt zijn onder andere:

Barbecue: De slagerbarbecue (zo'n een rechthoekige bak met rooster) aangepast zodat het rooster nu op 3 niveaus kan hangen.
Eettafel: Van de Ikea eettafel Norden die wij thuis hebben, heb ik de poten ingekort en er zwenkwielen onder gemonteerd, zodat hij makkelijk aan de kant gezet kan worden.
Carcassonne-kist: Ik ben een groot bord-spellen-fanaat, dus heb ik voor mijn Carcassonne-verzameling een mooie opbergkist gemaakt

Programmeren 


Programmeren doe ik graag voor de Arduino, de Raspberry Pi, de Pebble of een pc. De besturingssystemen waaronder ik programmeer zijn Linux (Debian, Mint of Raspbian) of Windows.

De talen waarin ik de meeste programma's schrijf zijn C (Arduino, Pebble), Pascal (Delphi/Lazarus), Python, PHP, Javascript (Pebble.js).

North Central Positronics, LTD.


Waarom North Central Positronics, LTD. als Blog-naam?
Naast bord-spellen-fanaat lees ik ook graag, vooral Stephen King.
Stephen King heeft een (nu) 8-delig verhaal geschreven genaamd De Donkere Toren, wat hijzelf lang zag als zijn levenswerk, de meeste van zijn andere verhalen zijn op de een of andere manier ook aan dit verhaal gekoppeld.

In de Donkere Toren staat op technische apparatuur altijd weer de naam North Central Positronics, LTD. voor en ik vond dit een mooie toepasselijke naam voor mijn blog omdat die ook voornamelijk om techniek draait.

De Donkere Toren speelt om een constructie die zich in het hart van het multiversum bevindt. (meer info over het verhaal lees je op Wikipedia).

Ik ben woonachtig in Utrecht en laatst vond ik (via de Stephen King Fanclub Nederland) een mooi plaatje van een verwilderde Dom-toren, zodat het net lijkt op wat Stephen King omschrijft als de Donkere Toren, vandaar dat deze ook als achtergrond op mijn blog staat.