Ecowitt API - diverse Wetterstationen

Begonnen von gent, 15 Dezember 2021, 20:52:55

Vorheriges Thema - Nächstes Thema

Elektronikus

Hier meine Definition:
define WeatherScreen GW1000_TCP 192.168.0.170 45000
attr WeatherScreen room KS300
#   DEF        192.168.0.170 45000
#   DevState   3
#   DeviceName 192.168.0.170:45000
#   FUUID      6540d137-f33f-bc07-fa0b-4a8d7f3fff580af6
#   I_GW1000_IP 192.168.0.170
#   I_GW1000_Port 45000
#   NAME       WeatherScreen
#   NOTIFYDEV  global
#   NR         231
#   NTFY_ORDER 50-WeatherScreen
#   STATE      opened
#   TYPE       GW1000_TCP
#   UpdateCmd  60
#   name       WeatherScreen
#   READINGS:
#     2023-10-31 11:36:56   state           opened
#
setstate WeatherScreen opened
setstate WeatherScreen 2023-10-31 11:36:56 state opened


Elektronikus

Das Modell ist die HP2550A, HW Version 2.0, Firmware Pro_V1.90, WiFi Firmware EasyWeather V1.6.6

Habe ich bei dem Modell eine Chance mit der GW1000_TCP Daten zu empfangen?

Schon mal vielen Dank

Elektronikus

Hallo Allerseits,
Ich habe jetzt ein kleines Python Program geschrieben, das die Daten der Wetterstation empfangen kann (Custom Setting der HP2550A) und schicke das dann über MQTT als JSON Struktur an FHEM

Vielleicht hilft das jemandem.

Viele Grüße
 
-----------
import nclib
import re
import paho.mqtt.client as mqtt
import json

# Define Regexp Filter
Tempsens =re.compile('^temp(.{0,2})f=(-?\d{1,2}\.\d*)$', re.IGNORECASE)
Humiditysens = re.compile('^humidit(y.{1,2}|y)=(\d{1,2})$', re.IGNORECASE)
Barosens = re.compile('^(.*)barom(rel|abs)(.{1,2})=(\d{1,2}\.\d*)$', re.IGNORECASE)
Winddirsens = re.compile('^wind(dir|dir_avg10m)=(\d{1,3}\.?\d?)$', re.IGNORECASE)
Windsens = re.compile('^wind(speed|spd)(mph|mph_avg10m)=(\d{1,3}.\d)$', re.IGNORECASE)
Gustsens = re.compile('^(wind|maxdaily)gus(t|tmph)=(\d{1,3}.\d)$')
Rainsens = re.compile('^(\D*)rain(ratein|in)=(\d{1,3}\.\d{3})$', re.IGNORECASE)
Solarsens = re.compile('^solarradiation=(\d{1,4}\.\d{1,3})$', re.IGNORECASE)
Batterystatus = re.compile('^(.*)batt(.{0,2})=(\d)$', re.IGNORECASE)
StationTimestamp = re.compile('^dateutc=(\d{4})-(\d{2})-(\d{2})\+(\d{2}):(\d{2}):(\d{2})$')
StationID = re.compile('^stationtype=(.*)$')
StationFrequency = re.compile('^freq=(\d{3})M$')
StationModel = re.compile('^model=(.*)$')

MQTT_HOST = 'Hier gehört die MQTT Serveradresse hin['
ACCESS_TOKEN = ''

client = mqtt.Client()
#client.on_connect = on_connect
#client.on_message = on_message


# Set access token
client.username_pw_set(ACCESS_TOKEN)

# Connect to Server using default MQTT port and 60 seconds keepalive interval
client.connect(MQTT_HOST, 1883, 600)

client.loop_start()

#------------------------------------------------------------------
# Read Weatherstation Message
#------------------------------------------------------------------
port = 46000
TCPserver = nclib.TCPServer(('0.0.0.0', int(port)))
for TCPclient in TCPserver:
    try:
      # if command was entered by the user
      # get output until dollar sign (bash --posix forces bash-X.X$)
      data = TCPclient.read_until('$')
      #print(data.decode('utf-8'), end="")  # print string of received bytes

    # handle exceptions and exiting
    except KeyboardInterrupt:
        print("\nKeyboardInterrupt")
        exit(1)
    except Exception as e:
        print("\nException Occurred\n")
        print(e)
        exit(1)
    datalines = data.decode('utf-8').split('&')
    print('\n')
    sensoren = {}
    for textelement in datalines:
        m = Tempsens.match(textelement)
        if m :
            print(f'temp{m[1]}C = {(float(m[2])-32.0)*5/9:.1f}°C')
            sensoren[f'temp{m[1]}C'] = f'{(float(m[2])-32.0)*5/9:.1f}'
           
        m = Barosens.match(textelement)
        if m :
            print (f'barom{m[1]}{m[2]}hPa = {29.262*33.86:.2f}hPa')
            sensoren[f'barom{m[1]}{m[2]}hPa'] = f'{29.262*33.86:.2f}'
           
        m = Humiditysens.match(textelement)
        if m :
            print(f'humidity{m[1][1:]}={m[2]}')
            sensoren[f'humidity{m[1][1:]}'] = f'{m[2]}'
           
        m = Winddirsens.match(textelement)
        if m :
            print (f'wind{m[1]} = {float(m[2]):.1f}°')
            sensoren[f'wind{m[1]}'] = f'{float(m[2]):.1f}'
           
        m = Windsens.match(textelement)
        if m :
            print (f'wind{m[1]}kmh{m[2][3:]} = {1.609344 * float(m[3]):.1f} km/h')
            sensoren[f'wind{m[1]}kmh{m[2][3:]}'] = f'{1.609344 * float(m[3]):.1f}'
           
        m = Gustsens.match(textelement)
        if m:
            print(f'{m[1]}gust{m[2][1:-3]} = {1.609344 * float(m[3]):.1f} km/h')
            sensoren[f'{m[1]}gust{m[2][1:-3]}kmh'] = f'{1.609344 * float(m[3]):.1f}'
           
        m = Rainsens.match(textelement)
        if m :
            print(f'{m[1]}rain{m[2][:-2]}mm = {float(m[3])*25.4:.1f} mm')
            sensoren[f'{m[1]}rain{m[2][:-2]}mm'] = f'{float(m[3])*25.4:.1f}'
           
        m = Solarsens.match(textelement)
        if m :
            print(f'solarradiation = {float(m[1]):.1f}')
            sensoren[f'solarradiation'] = f'{float(m[1]):.1f}'
           
        m = Batterystatus.match(textelement)
        if m :
            print(f'batt{m[1]+m[2]}={m[3]}')
            sensoren[f'batt{m[1]+m[2]}'] = f'{m[3]}'
           
        m = StationTimestamp.match(textelement)
        if m :
            print(f'StationTimestamp = {m[3]}.{m[2]}.{m[1]} {m[4]}:{m[5]}:{m[6]}')
            sensoren[f'StationTimestamp'] = f'{m[1]}-{m[2]}-{m[3]} {m[4]}:{m[5]}:{m[6]}'
           
        m = StationID.match(textelement)
        if m:
            print(f'StationID = {m[1]}')
            sensoren[f'StationID'] = f'{m[1]}'
           
        m = StationFrequency.match(textelement)
        if m:
            print(f'StationFreq = {m[1]} MHz')
            sensoren[f'StationFreqM'] = f'{m[1]}'
           
        m = StationModel.match(textelement)
        if m:
            print(f'StationModel = {m[1]}')
            sensoren[f'StationModel'] = f'{m[1]}'
           

    #------------------------------------------------------------------
    # Publish Weatherstation Message
    #------------------------------------------------------------------
    client.publish('tele/WeatherScreen/data', json.dumps(sensoren), 1)

    #break
   
#------------------------------------------------------------------
# MQTT aufräumen
#------------------------------------------------------------------

client.loop_stop()
client.disconnect()
TCPserver.close()
print("Disconnected :-)")
print('\n')

   

JoWiemann

Zitat von: Elektronikus am 01 November 2023, 20:15:45Hallo Allerseits,
Ich habe jetzt ein kleines Python Program geschrieben, das die Daten der Wetterstation empfangen kann (Custom Setting der HP2550A) und schicke das dann über MQTT als JSON Struktur an FHEM

Vielleicht hilft das jemandem.

Viele Grüße
   

Hallo,

klammere doch bitte den Code in Code Tags.

Grüße Jörg
Jörg Wiemann

Slave: RPi B+ mit 512 MB, COC (868 MHz), CUL V3 (433.92MHz SlowRF); FHEMduino, Aktuelles FHEM

Master: CubieTruck; Debian; Aktuelles FHEM

Elektronikus

# -*- coding:utf-8 -*-
import nclib
import re
import paho.mqtt.client as mqtt
import json
import time

# Define Regexp Filter
Tempsens =re.compile('^temp(.{0,2})f=(-?\d{1,2}\.\d*)$', re.IGNORECASE)
Humiditysens = re.compile('^humidit(y.{1,2}|y)=(\d{1,2})$', re.IGNORECASE)
Barosens = re.compile('^(.*)barom(rel|abs)(.{1,2})=(\d{1,2}\.\d*)$', re.IGNORECASE)
Winddirsens = re.compile('^wind(dir|dir_avg10m)=(\d{1,3}\.?\d?)$', re.IGNORECASE)
Windsens = re.compile('^wind(speed|spd)(mph|mph_avg10m)=(\d{1,3}.\d)$', re.IGNORECASE)
Gustsens = re.compile('^(wind|maxdaily)gus(t|tmph)=(\d{1,3}.\d)$')
Rainsens = re.compile('^(\D*)rain(ratein|in)=(\d{1,3}\.\d{3})$', re.IGNORECASE)
Solarsens = re.compile('^solarradiation=(\d{1,4}\.\d{1,3})$', re.IGNORECASE)
Batterystatus = re.compile('^(.*)batt(.{0,2})=(\d)$', re.IGNORECASE)
StationTimestamp = re.compile('^dateutc=(\d{4})-(\d{2})-(\d{2})\+(\d{2}):(\d{2}):(\d{2})$')
StationID = re.compile('^stationtype=(.*)$')
StationFrequency = re.compile('^freq=(\d{3})M$')
StationModel = re.compile('^model=(.*)$')

MQTT_HOST = 'ehinger-server'
ACCESS_TOKEN = ''

#time.sleep(120)

client = mqtt.Client()
#client.on_connect = on_connect
#client.on_message = on_message


# Set access token
client.username_pw_set(ACCESS_TOKEN)

# Connect to Server using default MQTT port and 60 seconds keepalive interval
client.connect(MQTT_HOST, 1883, 600)

client.loop_start()

#------------------------------------------------------------------
# Read Weatherstation Message
#------------------------------------------------------------------
port = 46000
TCPserver = nclib.TCPServer(('0.0.0.0', int(port)))

for TCPclient in TCPserver:
    try:
       # if command was entered by the user
       # get output until dollar sign (bash --posix forces bash-X.X$)
       data = TCPclient.read_until('$')
       #print(data.decode('utf-8'), end="")  # print string of received bytes

    # handle exceptions and exiting
    except KeyboardInterrupt:
        print("\nKeyboardInterrupt")
        exit(1)
    except Exception as e:
        print("\nException Occurred\n")
        print(e)
        exit(1)
    datalines = data.decode('utf-8').split('&')
    sensoren = {}
    for textelement in datalines:
        m = Tempsens.match(textelement)
        if m :
            sensoren[f'temp{m[1]}C'] = f'{(float(m[2])-32.0)*5/9:.1f}'
            continue

        m = Humiditysens.match(textelement)
        if m :
            sensoren[f'humidity{m[1][1:]}'] = f'{m[2]}'
            continue

        m = Batterystatus.match(textelement)
        if m :
            sensoren[f'batt{m[1]+m[2]}'] = f'{m[3]}'
            continue

        m = Winddirsens.match(textelement)
        if m :
            sensoren[f'wind{m[1]}'] = f'{float(m[2]):.1f}'
            continue

        m = Windsens.match(textelement)
        if m :
            sensoren[f'wind{m[1]}kmh{m[2][3:]}'] = f'{1.609344 * float(m[3]):.1f}'
            continue

        m = Gustsens.match(textelement)
        if m:
            sensoren[f'{m[1]}gust{m[2][1:-3]}kmh'] = f'{1.609344 * float(m[3]):.1f}'
            continue

        m = Rainsens.match(textelement)
        if m :
            sensoren[f'{m[1]}rain{m[2][:-2]}mm'] = f'{float(m[3])*25.4:.1f}'
            continue

        m = Barosens.match(textelement)
        if m :
            sensoren[f'barom{m[1]}{m[2]}hPa'] = f'{float(m[4])*33.86:.2f}'
            continue

        m = Solarsens.match(textelement)
        if m :
            sensoren[f'solarradiation'] = f'{float(m[1]):.1f}'
            continue

        m = StationTimestamp.match(textelement)
        if m :
            sensoren[f'StationTimestamp'] = f'{m[1]}-{m[2]}-{m[3]} {m[4]}:{m[5]}:{m[6]}'
            continue

        m = StationID.match(textelement)
        if m:
            sensoren[f'StationID'] = f'{m[1]}'
            continue

        m = StationFrequency.match(textelement)
        if m:
            sensoren[f'StationFreqM'] = f'{m[1]}'
            continue

        m = StationModel.match(textelement)
        if m:
            sensoren[f'StationModel'] = f'{m[1]}'
           

    #------------------------------------------------------------------
    # Publish Weatherstation Message
    #------------------------------------------------------------------
    client.publish('tele/WeatherScreen/data', json.dumps(sensoren), 1)

    #break
   
#------------------------------------------------------------------
# MQTT aufräumen
#------------------------------------------------------------------

client.loop_stop()
client.disconnect()
TCPserver.close()
print("Disconnected :-)")
print('\n')




Elektronikus

Anbindung einer dnt WeatherScreen PRO an FHEM

Mein Modell ist die HP2550A, HW Version 2.0, Firmware Pro_V1.90, WiFi Firmware EasyWeather V1.6.6

Ich habe FHEM auf einem Raspi4 und einen mosquitto MQTT server für meine Heimautomatisierung verwendet.

Ziel war es, alle Daten lokal zu handhaben. Deswegen konnte ich auch die Implementierten Server nicht verwenden.
Dankenswerterweise kann die WeatherScreen PRO aber einen fremden Server ansprechen und dort habe ich meinen Raspi4 eingetragen.

Als Gegenstelle musste ich jetzt noch einen Server aufsetzen, der die Daten empfängt und für FHEM aufbereitet.

Als Dateinamen habe ich Read_WeatherScreen_Pro.py verwendet:
Bitte noch <hier den Namen des MQTT Servers eintragen> durch den richtigen Namen ersetzen

# -*- coding:utf-8 -*-
import nclib
import re
import paho.mqtt.client as mqtt
import json
import time

# Define Regexp Filter
Tempsens =re.compile('^temp(.{0,2})f=(-?\d{1,2}\.\d*)$', re.IGNORECASE)
Humiditysens = re.compile('^humidit(y.{1,2}|y)=(\d{1,2})$', re.IGNORECASE)
Barosens = re.compile('^(.*)barom(rel|abs)(.{1,2})=(\d{1,2}\.\d*)$', re.IGNORECASE)
Winddirsens = re.compile('^wind(dir|dir_avg10m)=(\d{1,3}\.?\d?)$', re.IGNORECASE)
Windsens = re.compile('^wind(speed|spd)(mph|mph_avg10m)=(\d{1,3}.\d)$', re.IGNORECASE)
Gustsens = re.compile('^(wind|maxdaily)gus(t|tmph)=(\d{1,3}.\d)$')
Rainsens = re.compile('^(\D*)rain(ratein|in)=(\d{1,3}\.\d{3})$', re.IGNORECASE)
Solarsens = re.compile('^solarradiation=(\d{1,4}\.\d{1,3})$', re.IGNORECASE)
Batterystatus = re.compile('^(.*)batt(.{0,2})=(\d)$', re.IGNORECASE)
StationTimestamp = re.compile('^dateutc=(\d{4})-(\d{2})-(\d{2})\+(\d{2}):(\d{2}):(\d{2})$')
StationID = re.compile('^stationtype=(.*)$')
StationFrequency = re.compile('^freq=(\d{3})M$')
StationModel = re.compile('^model=(.*)$')

MQTT_HOST = '<hier den Namen des MQTT Servers eintragen >'
ACCESS_TOKEN = ''

#time.sleep(120)

client = mqtt.Client()
#client.on_connect = on_connect
#client.on_message = on_message


# Set access token
client.username_pw_set(ACCESS_TOKEN)

# Connect to Server using default MQTT port and 60 seconds keepalive interval
client.connect(MQTT_HOST, 1883, 600)

client.loop_start()

#------------------------------------------------------------------
# Read Weatherstation Message
#------------------------------------------------------------------
port = 46000
TCPserver = nclib.TCPServer(('0.0.0.0', int(port)))

for TCPclient in TCPserver:
    try:
       # if command was entered by the user
       # get output until dollar sign (bash --posix forces bash-X.X$)
       data = TCPclient.read_until('$')
       #print(data.decode('utf-8'), end="")  # print string of received bytes

    # handle exceptions and exiting
    except KeyboardInterrupt:
        print("\nKeyboardInterrupt")
        exit(1)
    except Exception as e:
        print("\nException Occurred\n")
        print(e)
        exit(1)
    datalines = data.decode('utf-8').split('&')
    sensoren = {}
    for textelement in datalines:
        m = Tempsens.match(textelement)
        if m :
            sensoren[f'temp{m[1]}C'] = f'{(float(m[2])-32.0)*5/9:.1f}'
            continue

        m = Humiditysens.match(textelement)
        if m :
            sensoren[f'humidity{m[1][1:]}'] = f'{m[2]}'
            continue

        m = Batterystatus.match(textelement)
        if m :
            sensoren[f'batt{m[1]+m[2]}'] = f'{m[3]}'
            continue

        m = Winddirsens.match(textelement)
        if m :
            sensoren[f'wind{m[1]}'] = f'{float(m[2]):.1f}'
            continue

        m = Windsens.match(textelement)
        if m :
            sensoren[f'wind{m[1]}kmh{m[2][3:]}'] = f'{1.609344 * float(m[3]):.1f}'
            continue

        m = Gustsens.match(textelement)
        if m:
            sensoren[f'{m[1]}gust{m[2][1:-3]}kmh'] = f'{1.609344 * float(m[3]):.1f}'
            continue

        m = Rainsens.match(textelement)
        if m :
            sensoren[f'{m[1]}rain{m[2][:-2]}mm'] = f'{float(m[3])*25.4:.1f}'
            continue

        m = Barosens.match(textelement)
        if m :
            sensoren[f'barom{m[1]}{m[2]}hPa'] = f'{float(m[4])*33.86:.2f}'
            continue

        m = Solarsens.match(textelement)
        if m :
            sensoren[f'solarradiation'] = f'{float(m[1]):.1f}'
            continue

        m = StationTimestamp.match(textelement)
        if m :
            sensoren[f'StationTimestamp'] = f'{m[1]}-{m[2]}-{m[3]} {m[4]}:{m[5]}:{m[6]}'
            continue

        m = StationID.match(textelement)
        if m:
            sensoren[f'StationID'] = f'{m[1]}'
            continue

        m = StationFrequency.match(textelement)
        if m:
            sensoren[f'StationFreqM'] = f'{m[1]}'
            continue

        m = StationModel.match(textelement)
        if m:
            sensoren[f'StationModel'] = f'{m[1]}'


    #------------------------------------------------------------------
    # Publish Weatherstation Message
    #------------------------------------------------------------------
    client.publish('tele/WeatherScreen/data', json.dumps(sensoren), 1)

    #break

#------------------------------------------------------------------
# MQTT aufräumen
#------------------------------------------------------------------

client.loop_stop()
client.disconnect()
TCPserver.close()
print("Disconnected :-)")
print('\n')
unter /home/pi/Read_WeatherScreen_Pro.py



Dann einen Service mit dem Namen Wetterstation.service anlegen:
[Unit]
Description=Oeffnet Port 46000, wartet auf Messages und sendet diese an MQTT
After=anzeige.service

[Service]
ExecStart=/usr/bin/python3 -u /home/pi/Read_WeatherScreen_Pro.py
WorkingDirectory=/home/pi/myscript
StandardOutput=inherit
StandardError=inherit
RestartSec=5s
Restart=always
User=pi

[Install]
WantedBy=multi-user.target

und mit
sudo cp ./Wetterstation.service /lib/systemd/system/ ins richtige Verzeichnis kopieren.

Starten kann man das Ganze dann mit
sudo systemctl start Wetterstation.servicetesten mit
sudo systemctl status Wetterstation.serviceund dauerhaft verankern mit
sudo systemctl enable Wetterstation.service

Beta-User

#36
Moin zusammen,

habe seit kurzem einen WittyBoy mit GW2000A, V3.1.3. "Eigentlich" wäre mein Plan gewesen, den Außensensor schlicht per Signalduino (Mapleduino, um genau zu sein) anzuzapfen, aber der scheint (!) auf 868MHz gar nichts zu empfangen => vertagt auf ein andermal...

Die HTTPMOD-Variante funktionierte zwar, hat mir aber teils Readings generiert, die für Interpretationen offen waren.

Dann habe ich mir das Modul mal näher angesehen. Das hat mit der aktuellen fw-Version des Gateways zuerst auch nicht wirklich funktioniert, habe daher ein paar kleinere Änderungen vorgenommen:
- Wenn jetzt was unbekannt ist, sollte schlicht ein passendes "kenne ich nicht"-Error-Reading geschrieben werden, aber der Rest durchlaufen (ist nicht abschließend getestet, denn)
- die neuen Datenfelder für das 2000-er GW sind nachgepflegt;
- der Start erfolgt jetzt nicht mehr per notifyFn, sondern per timer, die ersten Daten sollten bei einem FHEM-Start dann nach einer Minute eintrudeln.

Habe vor, bei Gelegenheit mal ein generelles cleanup von dem Modulchen zu machen und es dann ggf. bei Interesse auch (vermutlich in contrib) einzuchecken. Habe aber nichts dagegen, wenn sich ein anderer Freiwilliger finden würde.

Zum Sensor selbst (WS90): bin ziemlich begeistert. Die Werte sehen plausibel aus, es ist alles da, was man so braucht, und dann ist es im Großen und Ganzen noch solarbetrieben (Batterie für die Notversorgung). Bin mal gespannt, wie das langfristig funktioniert. Und: das Format ist so, dass es auch meine bessere Hälfte optisch akzeptabel findet...

Wg. Signalduino (auf dem Maple läuft die letzte Dev von Ralf, https://forum.fhem.de/index.php?topic=111653.0, mit dem SignalDuionAdv-Modul) werde ich auch dranbleiben, hat aber im Moment keine Prio.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Beta-User

Erster Iterationsschritt in der Überarbeitung. Perlcritic hat nur noch wenig (auf level 3) zu mosern...

Noch nicht intensiv getestet.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files