Neues Python FHEM API-Modul auf PyPI

Begonnen von domschl, 01 Januar 2017, 12:15:41

Vorheriges Thema - Nächstes Thema

domschl

FHEM User, die Python verwenden wollen, um auf den Server zuzugreifen, können das Modul fhem von PyPI verwenden.
Unterstützt wird Lesen und Senden von FHEM readings und commands. Das Modul implementiert Background threading mit Python Queue für Fhem events. Fhem events werden als Python dictionaries aufbereitet and eine Python Queue übergeben.

Installation:
pip install fhem

Projekt-Source und Doku:

Kurzes Beispiel: (mehr Beispiele und Doku siehe Github)

import fhem
import logging

logging.basicConfig()

fh = fhem.Fhem("myserver.home.org")
# Send a command to FHEM (this automatically connects())
fh.send_cmd("set lamp on")
# Get a specific reading from a device
temp = fh.get_dev_reading("LivingThermometer", "temperature")

Brutzel

Super! Genau was ich gesucht habe!
Funktioniert prima!
:)

Vielen Dank dafür!

Gruß
Brutzel

tmachowinski

Guten Abend zusammen!
Das Modul kommt mir irgenwie ziemlich recht, ich bin gerade dabei, mit einem Raspberry verschiedene Techniken auszuprobieren. Ich habe zwar bisher noch nicht sehr viel mit python oder perl direkt gearbeitet, aber einiges erschließt sich mir durch Lesen von Tutorials und manpages etc.

Mir taucht beim basteln jetzt ein konkretes hindernis auf. Ich möchte mithilfe der funktion .send_cmd ein reading in einem dummy device setzen.
Dadurch soll ein per python ausgelesener DHT22 Sensor in fhem eingebaut werden.

also in fhem:
define DHT dummy
attr stateFormat T:temperature H:humidity


in python nutze ich die AdafruitDHT module. Die werfen mir Werte in die Variablen mit den namen temperature und humidity

jetzt möchte ich per python das reading T auf den Wert aus der variablen temperature setzen.

fh.send_cmd("setreading DHT T temperature")

wie bringe ich python jetzt bei, den Wert statt des Variablennamens einzusetzen?

Auch auf die Gefahr hin, dass die Frage mit wenig Basiswissen in Python zu beantworten ist, würde ich mich über eine Antwort freuen.

grüße Thomas

jorge

Hallo tmachowinski,
bastle gerade auch an der api. Bei mir läuft die Variablenübergabe so:

fh.send_cmd("setreading DHT T  "+str(<variable.num>))

LG Jorge
FHEM.RaspberryPi 2 (HM, 1Wire, Callmonitor.FB 7490, GPIO, I2C, MQTT-Server, MCP23018)
FHEM.RaspberryPi  (FHEM2FHEM, CUL, FS20)
FHEM.RPiZeroW (I2C, 1Wire, python.api, XiaomiBTLESens.MQTT)
FHEM.Win7 (FHEM2FHEM,DBLOG.MySql)
ESPEasy (WEMOSD1, I2C, Analog, 1Wire), Sonoff_T1_3ch, Mobotix QM25, robonect

Chilia

Hi,

danke, schönes Modul! Vor allem für Leute die sich in Python etwas wohler fühlen als in Perl ;-)

Ich verwende es um Daten von meinem Geigerzähler in FHEM Readings umzuwandeln (https://forum.fhem.de/index.php/topic,71904.0.html).

Liebe Grüße
  Christian

satprofi

#5
Hallo.
Beim aufruf bekomme ich dies als Antwort:
AttributeError: 'module' object has no attribute 'Fhem'

Hat wer infos?

Danke
gruss
-----------------------------------------------------------------------
beelink miniPC - Fhem 6.x CUL 868, FS20, NetIO230 CUL 433
HMLAN, HM-CC-RT-DN,Homematic Actoren,LD382A,Telegram

Reinhart

Hallo domschl

Ich habe jetzt dein Modul in Betrieb genommen weil es genau das ist was ich suche!

Leider bekomme ich eine Fehlermeldung beim parsen von JSON.

('E - Failed to decode json, exception raised.', '\xff\xfd\x00{\n  "Arg":"FHT_Wz_Fussb",\n  "Results": [\n  {\n    "Name":"FHT_Wz_Fussb",\n    "PossibleSets":"day day-temp:on,off,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.0,12.5,13.0,13.5,14.0,14.5,15.0,15.5,16.0,16.5,17.0,17.5,18.0,18.5,19.0,19.5,20.0,20.5,21.0,21.5,22.0,22.5,23.0,23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0,28.5,29.0,29.5,30.0 desired-temp:on,off,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.0,12.5,13.0,13.5,14.0,14.5,15.0,15.5,16.0,16.5,17.0,17.5,18.0,18.5,19.0,19.5,20.0,20.5,21.0,21.5,22.0,22.5,23.0,23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0,28.5,29.0,29.5,30.0 fri-from1:time fri-from2:time fri-to1:time fri-to2:time holiday1 holiday2 hour lowtemp-offset manu-temp:on,off,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.0,12.5,13.0,13.5,14.0,14.5,15.0,15.5,16.0,16.5,17.0,17.5,18.0,18.5,19.0,19.5,20.0,20.5,21.0,21.5,22.0,22.5,23.0,23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0,28.5,29.0,29.5,30.0 minute mode mon-from1:time mon-from2:time mon-to1:time mon-to2:time month night-temp:on,off,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.0,12.5,13.0,13.5,14.0,14.5,15.0,15.5,16.0,16.5,17.0,17.5,18.0,18.5,19.0,19.5,20.0,20.5,21.0,21.5,22.0,22.5,23.0,23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0,28.5,29.0,29.5,30.0 report1 report2 sat-from1:time sat-from2:time sat-to1:time sat-to2:time sun-from1:time sun-from2:time sun-to1:time sun-to2:time thu-from1:time thu-from2:time thu-to1:time thu-to2:time tue-from1:time tue-from2:time tue-to1:time tue-to2:time wed-from1:time wed-from2:time wed-to1:time wed-to2:time windowopen-temp:on,off,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.0,12.5,13.0,13.5,14.0,14.5,15.0,15.5,16.0,16.5,17.0,17.5,18.0,18.5,19.0,19.5,20.0,20.5,21.0,21.5,22.0,22.5,23.0,23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0,28.5,29.0,29.5,30.0 year",\n    "PossibleAttrs":"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 IODev do_not_notify:1,0 model:fht80b dummy:1,0 showtime:1,0 retrycount minfhtbuffer lazy tmpcorr ignore:1,0 event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading DbLogExclude DbLogInclude HKurve actualRoom alexaName alexaRoom attributesExclude captionGroup captionRoom cmdIcon defined_by description devStateIcon devStateStyle disable fp_Grundriss genericDeviceType:security,ignore,switch,outlet,light,blind,thermometer,thermostat,contact,garage,window,lock homebridgeMapping:textField-long icon index item00 item01 item02 item03 item04 item05 item06 item07 item08 item09 item1 item10 item11 item12 item13 item14 item15 item16 item17 item18 item19 item2 item20 item21 item22 item23 item24 item25 item26 item27 item28 item29 item3 item30 item31 item32 item33 item34 item35 item36 item37 item38 item39 item4 item40 item41 item42 item43 item44 item5 item6 model sortby subType suffix valvesFHT_Kueche valvesFHT_KuecheGewichtung valvesFHT_NinaGewichtung valvesFHT_WohnzimmerGewichtung valvesFHT_WohnzimmerOGGewichtung valvesFHT_Wz_FussbGewichtung webCmd webCmdLabel:textField-long widgetOverride yaf_1 yaf_2 yaf_3 yaf_4 yaf_5 yaf_6 userattr",\n    "Internals": {\n      "COC_MSGCNT": "595",\n      "COC_RAWMSG": "810c04xx0909a00106080000367b",\n      "COC_RSSI": "-50",\n      "COC_TIME": "2017-12-21 10:54:26",\n      "CODE": "0608",\n      "DEF": "0608",\n      "LASTInputDev": "COC",\n      "MSGCNT": "595",\n      "NAME": "FHT_Wz_Fussb",\n      "NR": "538",\n      "STATE": "measured-temp: 22.9",\n      "TYPE": "FHT"\n    },\n    "Readings": {\n      "actuator": { "Value":"48%", "Time":"2017-12-21 10:54:26" },\n      "actuator_": { "Value":"048", "Time":"2017-12-21 10:54:26" },\n      "battery": { "Value":"ok", "Time":"2017-12-21 10:42:58" },\n      "desired-temp": { "Value":"22.5", "Time":"2017-12-21 04:46:26" },\n      "lowtemp": { "Value":"ok", "Time":"2017-12-21 10:42:58" },\n      "measured-temp": { "Value":"22.9", "Time":"2017-12-21 10:42:57" },\n      "state": { "Value":"measured-temp: 22.9", "Time":"2017-12-21 10:42:57" },\n      "temperature": { "Value":"22.9", "Time":"2017-12-21 10:42:57" },\n      "warnings": { "Value":"none", "Time":"2017-12-21 10:42:58" },\n      "window": { "Value":"closed", "Time":"2017-12-21 10:42:58" },\n      "windowsensor": { "Value":"ok", "Time":"2017-12-21 10:42:58" }\n    },\n    "Attributes": {\n      "IODev": "COC",\n      "event-on-change-reading": ".*",\n      "icon": "hc_wht_regler",\n      "lazy": "1",\n      "model": "fht80b",\n      "room": "FHT_Regler,_Wohnzimmer",\n      "userReadings": "actuator_ {sprintf(\\u0022%.3d\\u0022, ReadingsNum($name,\\u0022actuator\\u0022,0))}",\n      "yaf_1": "id=102,name=fht80,showicon=1,showlabel=1,fhemname=FHT_Wz_Fussb,y_pos=611,x_pos=195,labeltype=Name,",\n      "yaf_5": "id=117,name=generic,showicon=1,fhemname=FHT_Wz_Fussb,showlabel=0,y_pos=422,x_pos=386,labeltype=Name,statetype=measured-temp,"\n    }\n  }  ],\n  "totalResultsReturned":1\n}\n\n')


Ich bin mir nicht sicher ob es diese Zeichen am Anfang sind:
\xff\xfd\x00

Meine Umgebung: Rasperry B+ mit Stretch und alle Updates. Deine letzte Version vom Github.

Hast du eine Idee an was das liegen kann, bzw. gibt es eventuell neuere Librarys die man einsetzen kann. Eingelesen wird ja schon mal. Übrigens ist es egal welches Reading ich verwende, der Abbruch bleibt bei allen gleich.

LG
Reinhart

FHEM auf Raspy4 mit Bullseye + SSD, Homematic, ESP8266, ESP32, Sonoff, eBus, NanoCUL, MapleCUL, , MQTT2, Alexa

domschl

#7
Hallo Reinhart,

sorry, ich habe das erst gerade gelesen.

Heute habe ich eine neuere Version (0.5.0) rausgegeben, aber ich befürchte, das wird Dein Problem nicht lösen.

Habe ich richtig verstanden, daß der Fhem server auf Raspberry B+ läuft? Welches Betriebssystem und welche Python-Version setzt Du als Client ein?

(am Besten auch mal ein kurzes Code-Fragment anhängen, setzt Du z.b. HTTP oder Telnet ein?)

Gruß Dominik.

Reinhart

Danke für deine Antwort!

ich habe es jetzt ganz primitiv gelöst, ich benutze die "fhem.pl" und mache es mit "list" und dem gewünschten Devicenamen, das geht schnell genug und reicht für meine Zwecke.

def get_ebus(fhemdevice,cutter):
   global data 
   # /opt/fhem/fhem.pl 10.0.0.5:7072 'list PumpeWatt'| grep 'STATE' |/usr/bin/awk '{print $3}'
   cmd= "/opt/fhem/fhem.pl " + fhemhost + ":7072 'list " + fhemdevice + "'| grep 'STATE' |/usr/bin/awk '{print $" + cutter +"}'"
   data = subprocess.check_output(cmd, shell = True )
   data = data.rstrip('\)\n')
   data = data.strip()
   return data


Ich steuere damit ein Oled direkt vom Raspi und zeige damit ein paar Werte aus FHEM an. Am Raspi braucht auch kein FHEM installiert sein, die fhem.pl genügt. Während andere Daten im Display angezeigt werden, hole ich schon die nächsten somit gibt es merklich auch keine Wartezeit.

LG
Reinhart
FHEM auf Raspy4 mit Bullseye + SSD, Homematic, ESP8266, ESP32, Sonoff, eBus, NanoCUL, MapleCUL, , MQTT2, Alexa

tobox

Die aktuelle Version 0.5.1 läuft nicht mit obigem Beispiel. Wenn man nach "import fhem" noch folgendes einfügt, geht es:


import logging
logging.basicConfig()

Huntercover

#10
gibt es eine Möglichkeit hier direkt einen fhem anzugeben der real auf einem anderen Pi läuft?
Ich bekomme so leider diesen Fehler:
  ERROR:fhem:Failed to connect to 192.168.178.24:7072

und werde dann wohl fhem auf jedem Pi samt FHEM2FHEM nutzen müssen ..

@tobox: Danke, den Tipp habe ich benötigt :-)

domschl

@tobox: ich konnte die Probleme mit Logging zwar nicht nachvollziehen, habe aber oben das Beispiel ergänzt.

@Huntercover: die python-API sollte auf jeden Fall auch über Netz funktionieren. Was passiert den, wenn Du mit Telnet auf 192.168.178.24:7072 zugreifst?
Wie sieht das Code-Schnipsel aus, mit dem Du den connect versuchst?
Ich der Telnet-port auf FHEM auch aktiv? Netzwerk-Probleme ausgeschlossen?

Huntercover

@domschl: Genial: lag an der nicht vorhandenen telnet Definition auf dem anderen FHEM / Pi! Danke für den trivialen Tipp :-)

Komisch nur, dass ich mich nicht erinnern kann an telnet überhaupt was selbst einzustellen (bei beiden Pi's).
Irgendwie hat der lokale fhem das selbst angelegt oder was auch immer?!

satprofi

hallo.
was genau ist an dem modul besonders?
ich übergebe werte in meinen pythonscripts folgend


#Werte an FHEM uebergeben
os.system('perl /opt/fhem/fhem.pl 7072 "setreading Xtender_SOC SOC '+str(SOC)+'"')


Gesendet mit Tapatalk

gruss
-----------------------------------------------------------------------
beelink miniPC - Fhem 6.x CUL 868, FS20, NetIO230 CUL 433
HMLAN, HM-CC-RT-DN,Homematic Actoren,LD382A,Telegram

domschl

Reines senden an FHEM geht natürlich auch auf Deinem Weg.

Spannender wird es, wenn Werte gelesen werden sollen, oder irgend eine Form von Authentifizierung verwendet wird.
Außerdem bietet das Modul auch noch Events bei Änderungen von Werten im FHEM.

Das alles mit os.system() zu realisieren, dürfte wohl eine Herausforderung sein ;-)

Eine komplette API-Beschreibung gibt's hier:

* https://github.com/domschl/python-fhem

satprofi

in diesem falle, hast recht. werd es mir mal ansehen.

Gesendet mit Tapatalk

gruss
-----------------------------------------------------------------------
beelink miniPC - Fhem 6.x CUL 868, FS20, NetIO230 CUL 433
HMLAN, HM-CC-RT-DN,Homematic Actoren,LD382A,Telegram

stkr002


Hallo,

ist nicht ganz das Thema, aber vielleicht kann mir jemand helfen: Ich möchte aus FHEM heraus Python-Skripte starten. Das ist mir bisher leider nicht gelungen. Ich kann zwar grundsätzlich die Python-Skripte aufrufen, aber diese werden - warum auch immer - nicht ausgeführt.

Derzeit behelfe ich mir mit dem API-Modul: Ich habe eine Python-Dauerschleife, welche diverse FHEM readings abfragt und dann die entsprechenden python-Skripte startet. Funzt zwar, aber der Direktstart aus FHEM wäre irgendwie eleganter...

mumpitzstuff


Superwutz

#18
Huhu,

ich versuche momentan hiermit ein Userreading von mir zu verändern.
Das klappt leider irgendwie nicht.

So wird in fhem mein reading definiert:
attr Heizstab userReadings Verbrauch {2000}

So versuche ich es in python zu beschreiben:
fh.send_cmd("setreading " + s + " Verbrauch " + str(cpc))

s ist hier der devicename und cpc mein (int) Wert..
Leider ändert sich in fhem gar nichts bei dem Reading..
FHEM unter Windows
Drölfzig Homematic IP Devices

ralfi

Hallöchen, ich hätte da mal eine Frage und zwar:

ich habe das Modul ganz normal mit pip install fhem installiert und versuche mich nun mit dem FHEM Server zu connecten.

Script:

import fhem

fh = fhem.Fhem(.....

Dabei kriege ich folgende Fehlermeldung: AttributeError: 'module' object has no attribute 'Fhem'

wie kann das den Sein???

domschl

Die wahrscheinliche Erklärung ist die Wahl des Filenames Deines scripts.

Es heißt doch nicht etwa fhem.py? ;)

Dann import Dein script nämlich nicht das fhem-Module, sondern sich selbst...

TK67

Hallo domschl,

irgendwie komme ich da im Moment nicht weiter.

Ein fh.get_dev_reading("Victron", "BetriebsartValue") liefert mir
{u'BetriebsartValue': 3, u'Betriebsart': u'Bulk '}

Ein  fh.get_dev_reading("Victron", "BetriebsartValue") bringt mir noch mehr Ausgaben
{u'BetriebsartValue': {u'Value': 3, u'Time': datetime.datetime(2019, 6, 1, 12, 26, 47)}, u'Betriebsart': {u'Value': u'Bulk ', u'Time': datetime.datetime(2019, 6, 1, 12, 26, 47)}}

Internals:
   DEF        /dev/serial/by-id/usb-VictronEnergy_BV_VE_Direct_cable_VE2P2V9M-if00-port0@19200
   DeviceName /dev/serial/by-id/usb-VictronEnergy_BV_VE_Direct_cable_VE2P2V9M-if00-port0@19200
   FD         12
   FUUID      5c52f98f-f33f-e972-cec2-60b0e8e060a18a16
   NAME       Victron
   NR         63
   PARTIAL   
   STATE      Leistung: 230.00 W<br/>Batterie: 13.61 V<br/>Batterie: 16.50 A<br/>Ertrag heute: 0.76 kWh
   TYPE       VEDirect
   READINGS:
     2019-06-01 13:07:31   Betriebsart     Bulk
     2019-06-01 13:07:31   BetriebsartValue 3
     2019-06-01 13:07:31   DaySequenceNumber 316
     2019-06-01 13:07:31   Fehlermeldung   kein Fehler
     2019-06-01 13:07:31   Firmware        1.39
     2019-06-01 13:07:31   Lastausgang     eingeschaltet
     2019-06-01 03:43:48   state           opened
   SENDBUFFER:
     undef
Attributes:
   Darstellung_Ertrag kWh
   addLog     Maximale_Leistung_heute
   room       Solaranlage
   stateFormat Leistung: LeistungPanel_W<br/>Batterie: Spannung_V<br/>Batterie: Strom_A<br/>Ertrag heute: kWh_Ausbeute_heute


Wie komme ich jetzt an den Wert von "BetriebsartValue" also die 3 ? Es scheint so das alle Readings die gleich anfangen im Device, zusammen gefasst werden. Ich benutze zur Zeit die Version 0.6.1

Gruß TK67
FHEM auf Raspberry Pi 3 Model B+

domschl

Hallo,

fh.get_dev_reading(device, reading) (oder get_device_reading()) liefert ein python dictionary:


my_dict = fh.get_dev_reading("Victron", "BetriebsartValue")
print(my_dict)  # {u'BetriebsartValue': 3, u'Betriebsart': u'Bulk '}
betr_val = my_dict["BetriebsartValue"]
print(betr_val)   # Sollte jetzt '3' ausgeben.


kaskadiert (zwei ineinander verschachtelte dictionaries):

# Antwort von Fhem:
my_dict={u'BetriebsartValue': {u'Value': 3, u'Time': datetime.datetime(2019, 6, 1, 12, 26, 47)}, u'Betriebsart': {u'Value': u'Bulk ', u'Time': datetime.datetime(2019, 6, 1, 12, 26, 47)}}
print(my_dict['BetriebsartValue']['Value'])   # -> 3


Zu Python dictionaries, siehe z.b. hier:
https://www.w3schools.com/python/python_dictionaries.asp

Dom.

TK67

Danke für die prompte Antwort und den Link zu den Dictionaries.
Bin leider erst heute wieder dazu gekommen hier weiter zu machen und komme jetzt auch an meinen Zahlenwert.

Eine Frage ist allerdings noch offen, warum wird bei dem gleichen Befehl einmal ein Dictionarie gebildet und dann wiederum nicht.
Habe zum testen mal ein Dummy mit den 2 Readings erzeugt.

list versuch
Internals:
   FUUID      5cf6bacf-f33f-c80d-ddc2-5e09c99527f1887b
   NAME       versuch
   NR         528
   STATE      ???
   TYPE       dummy
   OLDREADINGS:
   READINGS:
     2019-06-04 21:23:59   Betriebsart     Bulk
     2019-06-04 21:23:23   BetriebsartValue 3
   helper:
     bm:
       dummy_Define:
         cnt        1
         dmx        -1000
         dtot       0
         dtotcnt    0
         mTS        1559673760.1605
         max        5.79357147216797e-05
         tot        5.79357147216797e-05
         mAr:
           HASH(0x6f4d3c0)
           versuch dummy
       dummy_Set:
         cnt        47
         dmx        -1000
         dtot       0
         dtotcnt    0
         mTS        1559675222.63004
         max        0.000472068786621094
         tot        0.00869655609130859
         mAr:
           HASH(0x6f4d3c0)
           versuch
           ?
Attributes:


Beispiel 1
ein fh.get_dev_reading("versuch", "BetriebsartValue") ergibt:
{u'BetriebsartValue': 3, u'Betriebsart': u'Bulk'}
ein len() auf die Ausgabe ergibt 2, was dann ja die Anzahl der Elemente dastellt

Beispiel 2
im Gegenzug ergibt fh.get_dev_reading("versuch", "Betriebsart") direkt den Wert des Readings:
Bulk
ein ensprechendes len() dann 4, wohl dann die länge des Strings.

Wieso dieses unterschiedliche Verhalten ?
Arbeite jetzt auch schon länger mit dem Modul und hatte eigentlich immer eine Ausgabe die ich direkt weiter verarbeiten konnte, sowie im Beispiel 2.
Scheinbar hatte ich dann wohl nur mit Readings zu tun die nicht einen weiteren Readingnamen in sich beinhalten, wie hier als Beispiel Betriebsart schon in BetriebsartValue steckt.

Ansonsten danke für ein klasse Modul, ohne das ich so manche Sachen gar nicht oder nur mit erheblichen Aufwand hätte umsetzen können.

Gruß TK67
FHEM auf Raspberry Pi 3 Model B+

domschl

Das ist schon merkwürdig.

Um rauszukriegen, wo der Fehler liegt, bitte folgendes ausprobieren

  • Komplettes Code-fragment hier reinkopieren (die erste Mail hatte einen Copy/Paste Fehler: Beides mal war BetriebsartValue verwendet, die Ausgabe passte dann nicht dazu.)
  • Logging am Anfang des codes anschalten:

import logging
logging.basicConfig(level=logging.DEBUG)

Log-Ausgaben dann bitte in die Antwort packen.

Dann sollten wir rausfinden können, an welcher Stelle es schief läuft.

Dom.

TK67

#25
Hab mal alles auf das nötigste verkleinert.

List vom Device
Internals:
   FUUID      5cf6bacf-f33f-c80d-ddc2-5e09c99527f1887b
   NAME       versuch
   NR         528
   STATE      off
   TYPE       dummy
   READINGS:
     2019-06-04 21:23:59   Betriebsart     Bulk
     2019-06-04 21:23:23   BetriebsartValue 3
     2019-06-06 13:21:20   state           off
   helper:
     bm:
       dummy_Set:
         cnt        37
         dmx        -1000
         dtot       0
         dtotcnt    0
         mTS        1559820074.08844
         max        0.0328681468963623
         tot        0.0684270858764648
         mAr:
           HASH(0x5ad1218)
           versuch
           on
Attributes:


Programmcode:
#!/usr/bin/python
# coding=utf8

import logging
import fhem

logging.basicConfig(level=logging.DEBUG)

fh = fhem.Fhem("192.168.178.14")
fh.connect()
print
print "-------Ausgabe von fh.get_dev_reading('versuch', 'BetriebsartValue')"
print fh.get_dev_reading('versuch', 'BetriebsartValue')
print
print "------Ausgabe von fh.get_dev_reading('versuch', 'Betriebsart')"
print fh.get_dev_reading('versuch', 'Betriebsart')
print
fh.close()

exit(0)


Ausgabe:
pi@raspberrypi:~ $ 1.py
DEBUG:Fhem:Creating socket...
INFO:Fhem:Connecting to 192.168.178.14:7072 without SSL
INFO:Fhem:Connected to 192.168.178.14:7072

-------Ausgabe von fh.get_dev_reading('versuch', 'BetriebsartValue')
WARNING:Fhem:Deprecation: use get_device_reading('device', 'reading') instead of get_dev_reading
DEBUG:Fhem:Sending: jsonlist2 NAME~versuch
DEBUG:Fhem:Connected, sending...
INFO:Fhem:Sent msg, len=23
INFO:Fhem:JSON answer received.
{u'BetriebsartValue': 3, u'Betriebsart': u'Bulk'}

------Ausgabe von fh.get_dev_reading('versuch', 'Betriebsart')
WARNING:Fhem:Deprecation: use get_device_reading('device', 'reading') instead of get_dev_reading
DEBUG:Fhem:Sending: jsonlist2 NAME~versuch
DEBUG:Fhem:Connected, sending...
INFO:Fhem:Sent msg, len=23
INFO:Fhem:JSON answer received.
Bulk

INFO:Fhem:Disconnected from fhem-server


Sehe da jetzt leider bei der Debug Ausgabe keine Unterschiede, bis auf natürlich das Ergebnis.

Das ganze lässt sich wohl auch erweitern, habe zu Testzwecken noch ein Reading "BetriebsartValueOld" erstellt, bei Abfrage dessen werden die anderen beiden Readings auch inkludiert:
print fh.get_dev_reading('versuch', 'BetriebsartValueOld')
{u'BetriebsartValueOld': 5, u'BetriebsartValue': 3, u'Betriebsart': u'Bulk'}

Gruß TK67


Nachtrag:

wenn ich jetzt alle Readings bis auf Betriebsart lösche
bekomme ich immer noch den Wert von Betriebsart, auch wenn ich das nicht mehr existierende fh.get_dev_reading('versuch', 'BetriebsartValue') abfrage
-------Ausgabe von fh.get_dev_reading('versuch', 'BetriebsartValue')
WARNING:Fhem:Deprecation: use get_device_reading('device', 'reading') instead of get_dev_reading
DEBUG:Fhem:Sending: jsonlist2 NAME~versuch
DEBUG:Fhem:Connected, sending...
INFO:Fhem:Sent msg, len=23
INFO:Fhem:JSON answer received.
Bulk


Irgendwas scheint hier fälschlicherweise als Wildcard zu arbeiten, könnte ich mir vorstellen.
FHEM auf Raspberry Pi 3 Model B+

domschl

Danke für die ausführliche Log-Information: In der Tat ein Bug!

Wenn ein Reading-Name einfach eine längere Version eines bereits existierenden Reading-Namens ist, dann gibt das Modul z.Zt. fälschlicherweise beide aus. Wie Du schon vermutet hast, liegt da mit den Wildcards was im argen.

Falls readings 'name' und 'nameplus' existieren, dann gibt eine Anfrage an 'nameplus' auch 'name' aus.

Ich guck mir das mal genauer an.

domschl

Ich denke ich habe das Problem:
https://github.com/domschl/python-fhem/issues/14
Ich bereite eine neue Version 0.6.2 vor.

Noch eine Anmerkung: Die Tatsache, dass manchmal ein dictionary und manchmal 'nur' ein Value ('Bulk') zurueckgegeben wird, liegt daran, dass Du eine alte 'deprecated' API verwendest. Wenn statt dessen 'get_device_reading()' (nicht `get_dev_reading()`) verwendt wird, klappt es und es kommt immer ein Dictionary.

domschl

python-fhem 0.6.2 ist nun auf pypi released: https://pypi.org/project/fhem/

Update mit:

pip install -U fhem

Neben kleiner Bugfixes wie dem Problem, daß bei ähnlichen Readings-Namen zu viele Antworten gegeben wurden, ist die Haupt-Neuheit ein automatisches Test-Framework mit Travis-CI.
Code-Änderungen werden jetzt automatisch gegen eine FHEM-Testinstallation getestet, für Python 2.7, 3.6, Telnet, SSL-Telnet, HTTP, HTTPS und Passwort-Checks.

Empfohlen wird die Verwendung von HTTP oder HTTPS.

Loredo

Ich finde den Namen des Pakets unglücklich gewählt, da es sich hier nicht um ein komplettes FHEM handelt.
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

TK67

Danke für die neue Version, das mit den ähnlichen Readings-Namen funktioniert jetzt ohne Probleme.
Eine Telnet Verbindung wirft mir jetzt allerdings bei jeder Abfrage eine Exception, der Wert wird aber ausgelesen.

Testabfrage : print fh.get_device_reading("test", "state")
Ausgabe : {u'Value': 1, u'Time': datetime.datetime(2019, 8, 19, 1, 46, 48)}

Debug-Log:
Aug 19 01:46:47 Sending: jsonlist2 NAME~test
Aug 19 01:46:47 Connected, sending...
Aug 19 01:46:47 Sent msg, len=20
Aug 19 01:46:47 Exception in non-blocking. Error: [Errno 11] Resource temporarily unavailable
Aug 19 01:46:47 JSON answer received.


Wäre nett wenn man da nochmal drüber schaut.

Gruß TK67
FHEM auf Raspberry Pi 3 Model B+

domschl

"Resource temporary unavailable" ist mit hoher Wahrscheinlichkeit einfach ein Timing-Problem:
Der Python-client schickt eine Anfrage, und erwartet dann "direkt" eine Antwort. Wenn der Server
eine etwas "gemütlichere" hardware verwendet, dann ist die Antwort nicht sofort verfügbar, was
eine "Resource temporary unavailable" exception erzeugt. Der client wiederholt dann die lese-
Anfrage und dann kommt die Antwort auch an.

Die Ausgabe mit der Exception ist also im Prinzip einfach überflüssig, da sich alles korrekt ver-
hält. Ich werde das beim nächsten update ändern, so daß nur bei wirklichen, permanenten
Timeouts ein Fehler kommt.

Bis dahin: Fehlermeldung einfach ignorieren. Was für einen FHEM-Server setzt Du ein? Ist
die Annahme mit Timing plausibel? Ich kann den Fehler nämlich nicht nachstellen, und auch
der automatische Test mit TravisCI zeigt keine Probleme.

Bug-Tracker: https://github.com/domschl/python-fhem/issues/18

Details zu ähnlichem Problem: https://stackoverflow.com/questions/39145357/python-error-socket-error-errno-11-resource-temporarily-unavailable-when-s

TK67

Bei mir läuft Fhem mit allen Updates auf einem Raspberry Pi 3 b+

Habe jetzt mal ein frisches System auf meinem Raspberry Pi 2 Testrechner mit Fhem aufgesetzt.
Dort zeigt sich auch das Timing Problem.

cat /etc/os-release:
PRETTY_NAME="Raspbian GNU/Linux 10 (buster)"
NAME="Raspbian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"


Obwohl dort weiter nichts läuft.
Top:
top - 12:51:45 up 56 min,  2 users,  load average: 0.00, 0.00, 0.00
Tasks: 111 total,   1 running, 110 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.2 us,  0.2 sy,  0.0 ni, 99.6 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :    926.1 total,    716.6 free,     72.7 used,    136.8 buff/cache
MiB Swap:    100.0 total,    100.0 free,      0.0 used.    795.6 avail Mem


Fehler ist bei mir auch reproduzierbar, hier mal eine Schleife mit time sleep von 5 Sekunden.
Aug 19 12:53:26 Sending: jsonlist2 NAME~test
Aug 19 12:53:26 Connected, sending...
Aug 19 12:53:26 Sent msg, len=20
Aug 19 12:53:26 Exception in non-blocking. Error: [Errno 11] Resource temporarily unavailable
Aug 19 12:53:26 JSON answer received.
Aug 19 12:53:31 ------------
Aug 19 12:53:31 Sending: jsonlist2 NAME~test
Aug 19 12:53:31 Connected, sending...
Aug 19 12:53:31 Sent msg, len=20
Aug 19 12:53:31 Exception in non-blocking. Error: [Errno 11] Resource temporarily unavailable
Aug 19 12:53:31 JSON answer received.
Aug 19 12:53:36 ------------
Aug 19 12:53:36 Sending: jsonlist2 NAME~test
Aug 19 12:53:36 Connected, sending...
Aug 19 12:53:36 Sent msg, len=20
Aug 19 12:53:36 Exception in non-blocking. Error: [Errno 11] Resource temporarily unavailable
Aug 19 12:53:36 JSON answer received.
Aug 19 12:53:41 ------------
Aug 19 12:53:41 Sending: jsonlist2 NAME~test
Aug 19 12:53:41 Connected, sending...
Aug 19 12:53:41 Sent msg, len=20
Aug 19 12:53:42 Exception in non-blocking. Error: [Errno 11] Resource temporarily unavailable
Aug 19 12:53:42 JSON answer received.
Aug 19 12:53:47 ------------
Aug 19 12:53:47 Sending: jsonlist2 NAME~test
Aug 19 12:53:47 Connected, sending...
Aug 19 12:53:47 Sent msg, len=20
Aug 19 12:53:47 Exception in non-blocking. Error: [Errno 11] Resource temporarily unavailable
Aug 19 12:53:47 JSON answer received.
FHEM auf Raspberry Pi 3 Model B+

domschl

Das ist schon verrückt. Ich habe noch einen alten Raspi-1 mit Fhem im Netz, und habe damit getestet.
Sowohl mit Py2 als auch Py3 kein Problem.

Ich vermute, daß der Unterschied dann im Netzwerk timing liegt.

Aber kein Problem, ich weiß wie ich das korrigieren kann. Kommt mit dem nächsten Release.

ch.eick

Hallo zusammen.

Ich bin reiner Python Anwender und versuche die python-fhem Kopplung zu nutzen

Als user fhem habe ich folgendes gemacht

$ pip install fhem
Collecting fhem
  Downloading https://www.piwheels.org/simple/fhem/fhem-0.6.2-py2.py3-none-any.whl
Installing collected packages: fhem
Successfully installed fhem-0.6.2


Der erste Test des python Skripts ohne das interface

import json
import asyncio
from vallox_websocket_api import Client

client = Client('<IP-Adresse Quelle>')
async def run():
    metrics = await client.fetch_metrics([
      'A_CYC_TEMP_EXHAUST_AIR',
      'A_CYC_TEMP_EXTRACT_AIR',
      'A_CYC_TEMP_OUTDOOR_AIR',
      'A_CYC_TEMP_SUPPLY_AIR',
      'A_CYC_TEMP_SUPPLY_CELL_AIR'
    ])

    from pprint import pprint
    pprint(json.dumps(metrics))

asyncio.get_event_loop().run_until_complete(run())


Output in der Shell

$ python3.5 ./test_ce_status_temp.py
('{"A_CYC_TEMP_SUPPLY_CELL_AIR": 23.1, "A_CYC_TEMP_EXTRACT_AIR": 24.1, '
'"A_CYC_TEMP_EXHAUST_AIR": 24.4, "A_CYC_TEMP_SUPPLY_AIR": 24.6, '
'"A_CYC_TEMP_OUTDOOR_AIR": 23.5}')



Nun der Versuch mit Interface

import json
import asyncio
from vallox_websocket_api import Client
import fhem

client = Client('<IP-Adresse Quelle>')
async def run():
    metrics = await client.fetch_metrics([
      'A_CYC_TEMP_EXHAUST_AIR',
      'A_CYC_TEMP_EXTRACT_AIR',
      'A_CYC_TEMP_OUTDOOR_AIR',
      'A_CYC_TEMP_SUPPLY_AIR',
      'A_CYC_TEMP_SUPPLY_CELL_AIR'
    ])

    from pprint import pprint
    pprint(json.dumps(metrics))

    fh = fhem.Fhem("<IP-Adresse Ziel>", protocol="http", port=8083)

    fh.send_cmd("setreading KWL output ", json.dumps(metrics))

asyncio.get_event_loop().run_until_complete(run())



$ python3.5 ./test_ce_status_temp.py
Traceback (most recent call last):
  File "./test_ce_status_temp.py", line 1, in <module>
    import fhem
ImportError: No module named 'fhem'


Die vorherige Installation von vallox_websocket_api wurde ebenfalls mit "pip install vallox_websocket_api" durchgeführt und das Modul wird gefunden. Wo liegt nun der Fehler beim fhem Modul?

Achtung der Name fhem als Modulname ist wirklich sehr unglücklich!!!

Gruß
    Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

domschl

Meine Vermutung ist hier, daß auf dem System noch python2 das Standard-Python ist, und daß die PIP Installation das Python-2 PIP verwendet hat, und somit fhem nur unter Python2 zur Verfügung steht. Kann mit:


pip --version


Überprüft werden. Falls das wirklich die Ursache ist, einfach die Py3 Version mit


pip3 install -U fhem


installieren. Zusätzlich kann das Modul einfach im REPL-Mode von Python getestet werden. Einfach Python3 ohne parameter aufrufen, und dann in der REPL einfach mal `import fhem` eingeben.

ch.eick

Okay,
eine eigene Teilantwort. Es muss natürlich in das richtige Python installiert werden, in meinem Fall python3.5


$ python3.5 -m pip install fhem
Collecting fhem
  Using cached https://www.piwheels.org/simple/fhem/fhem-0.6.2-py2.py3-none-any.whl
Installing collected packages: fhem
Successfully installed fhem-0.6.2

Der Rest wird wohl ein login Problem sein....ich schau mal ins fhem log

$ python3.5 ./test_ce_status_temp.py
('{"A_CYC_TEMP_SUPPLY_AIR": 24.3, "A_CYC_TEMP_EXTRACT_AIR": 24.1, '
'"A_CYC_TEMP_EXHAUST_AIR": 24.5, "A_CYC_TEMP_OUTDOOR_AIR": 23.2, '
'"A_CYC_TEMP_SUPPLY_CELL_AIR": 23.0}')
Failed to send msg, len=0, timed out
No valid answer on send when expecting csrf.
Failed to send msg, len=0, HTTP Error 401: Authorization Required
No valid answer on send when expecting csrf.
CSRF token not available!
Traceback (most recent call last):
  File "./test_ce_status_temp.py", line 23, in <module>
    asyncio.get_event_loop().run_until_complete(run())
  File "/usr/lib/python3.5/asyncio/base_events.py", line 466, in run_until_complete
    return future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
    result = coro.send(None)
  File "./test_ce_status_temp.py", line 21, in run
    fh.send_cmd("setreading KWL output ", json.dumps(metrics))
  File "/home/fhem/.local/lib/python3.5/site-packages/fhem/__init__.py", line 315, in send_cmd
    return self.send(msg, timeout=timeout)
  File "/home/fhem/.local/lib/python3.5/site-packages/fhem/__init__.py", line 277, in send
    ans = urlopen(ccmd, paramdata, timeout=timeout)
  File "/usr/lib/python3.5/urllib/request.py", line 163, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib/python3.5/urllib/request.py", line 466, in open
    response = self._open(req, data)
  File "/usr/lib/python3.5/urllib/request.py", line 484, in _open
    '_open', req)
  File "/usr/lib/python3.5/urllib/request.py", line 444, in _call_chain
    result = func(*args)
  File "/usr/lib/python3.5/urllib/request.py", line 1282, in http_open
    return self.do_open(http.client.HTTPConnection, req)
  File "/usr/lib/python3.5/urllib/request.py", line 1254, in do_open
    h.request(req.get_method(), req.selector, req.data, headers)
  File "/usr/lib/python3.5/http/client.py", line 1107, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python3.5/http/client.py", line 1152, in _send_request
    self.endheaders(body)
  File "/usr/lib/python3.5/http/client.py", line 1103, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python3.5/http/client.py", line 934, in _send_output
    self.send(msg)
  File "/usr/lib/python3.5/http/client.py", line 877, in send
    self.connect()
  File "/usr/lib/python3.5/http/client.py", line 849, in connect
    (self.host,self.port), self.timeout, self.source_address)
  File "/usr/lib/python3.5/socket.py", line 700, in create_connection
    sock.settimeout(timeout)
TypeError: an integer is required (got type str)
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

Zitat von: domschl am 21 August 2019, 16:31:58
Meine Vermutung ist hier, daß auf dem System noch python2 das Standard-Python ist, und daß die PIP Installation das Python-2 PIP verwendet hat, und somit fhem nur unter Python2 zur Verfügung steht. Kann mit:


pip --version


Überprüft werden. Falls das wirklich die Ursache ist, einfach die Py3 Version mit


pip3 install -U fhem


installieren. Zusätzlich kann das Modul einfach im REPL-Mode von Python getestet werden. Einfach Python3 ohne parameter aufrufen, und dann in der REPL einfach mal `import fhem` eingeben.

Sorry, das hat sich überschnitten.

Ich benutze Python heute das erste Mal. ;D
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

Hallo nochmal.

Ich habe dann erst noch fhem auf https umkonfiguriert...
Nun klappt die https Kopplung mit Userid und Passwort auch über das Python-fhem interface.

Und hier mein lauffähiges Skript

# import logging
# logging.basicConfig(level=logging.DEBUG)

import fhem
import json
import asyncio
from vallox_websocket_api import Client

import sys

kwl = sys.argv[1]
web = sys.argv[2]
usr = sys.argv[3]
pwd = sys.argv[4]


client = Client(kwl)
async def run():
    metrics = await client.fetch_metrics([
      'A_CYC_TEMP_EXHAUST_AIR',
      'A_CYC_TEMP_EXTRACT_AIR',
      'A_CYC_TEMP_OUTDOOR_AIR',
      'A_CYC_TEMP_SUPPLY_AIR',
      'A_CYC_TEMP_SUPPLY_CELL_AIR'
    ])

    message = json.dumps(metrics)

    from pprint import pprint
    pprint(message)

    fh = fhem.Fhem("" + web + "", protocol="https", port=8083, username="" + usr + "" , password="" + pwd + "")

    fh.send_cmd("setreading KWL output " + message)

asyncio.get_event_loop().run_until_complete(run())


Das fhem define, was die Daten sammelt und direkt mit expandJSON in einzelne readings aufteilt

defmod KWL expandJSON KWL:output:.\{.*}


Und ein Bild im Anhang

Viele Grüße
    Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

#39
Jetzt noch eine Frage, um das unschöne speichern von Benutzerkennung und Passwort zu umgehen.

Ist es möglich, wie bei einer ssl Verbindung, mit einem hinterlegten Key, auch ohne Passwort die Verbindung zu nutzen?
Das mit dem cafile habe ich nicht verstanden ;-)

Gruß
   Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

domschl

Wenn man auf dem FHEM-Server einen WEB-Zugang mit HTTPS ohne Passwort-Authentifizierung anlegt, dann kann das Python Modul diese Verbindung verwenden. Einfach dann kein username/password angeben.
Die Verbindung ist dann SSL-Encrypted, nutzt aber keine Benutzer-Authentifizierung.

Was der FHEM-Server meines Wissens nicht kann, ist der Zugang per public/private Key. Dazu müßte man dann wohl von VPN oder SSH ausweichen.

Alternativ kann man noch im Python-Script die Credentials von einer externen Datei einlesen. Damit sind User/Pwd zumindestens nicht mehr hart kodiert im Script. So macht es z.b. das Datenbank-Modul von FHEM für username/pwd vom externen SQL Server, die credentials liegen in einem externen File db.conf.

ch.eick

#41
Zitat von: domschl am 21 August 2019, 18:14:11
Wenn man auf dem FHEM-Server einen WEB-Zugang mit HTTPS ohne Passwort-Authentifizierung anlegt, dann kann das Python Modul diese Verbindung verwenden. Einfach dann kein username/password angeben.
Die Verbindung ist dann SSL-Encrypted, nutzt aber keine Benutzer-Authentifizierung.

Was der FHEM-Server meines Wissens nicht kann, ist der Zugang per public/private Key. Dazu müßte man dann wohl von VPN oder SSH ausweichen.

Alternativ kann man noch im Python-Script die Credentials von einer externen Datei einlesen. Damit sind User/Pwd zumindestens nicht mehr hart kodiert im Script. So macht es z.b. das Datenbank-Modul von FHEM für username/pwd vom externen SQL Server, die credentials liegen in einem externen File db.conf.

Hmmm, was ist das sicherste?

1) HTTPS ohne Passwort könnte jeder aufrufen, der ins netzt kommt.

2) Die Passwort Datei kann man lesen, wenn man auf dem System ist. Mit "chmod 600" nur der Eigentümer fhem.

3) Mit Ablage im fhem device und Skriptaufruf mit Parameter, wie in meinem Beispiel, kann jeder dran der fhem Zugang hat.

Was wäre Deine Empfehlung?

Ich kann noch kein Python. Hast Du ein Beispiel für die Dateivariante?

Viele Grüße
    Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

domschl

Ich denke, da ja wohl das script lokal auf dem FHEM server laufen wird, ist vermutlich die beste Idee, kein zusätzliches "Loch" ins FHEM zu bohren, und die user/pwd aus einer Datei zu lesen.

Am einfachsten speichert man die Datei als JSON-File:

pwd.json:

{
    "username": "ich",
    "password": "secretsauce"
}


Im Python kann man das lesen mit:

import json

try:
    with open('pwd.json', 'r') as f:
        credentials=json.load(f)
except Exception as e:
    print('Something went wrong: {}'.format(e))

print("User: {}".format(credentials["username"]))
print("Pwd: {}".format(credentials["password"]))


credentials ist dann ein Python-dictionary. Der username ist in credentials["username"] und das Passwort in credentials["password']

ch.eick

Super, es läuft  8)


# import logging
# logging.basicConfig(level=logging.DEBUG)

import fhem
import json
import asyncio
from vallox_websocket_api import Client

import sys
kwl = sys.argv[1]
web = sys.argv[2]

try:
    with open('pwd.json', 'r') as f:
        credentials=json.load(f)
except Exception as e:
    print('Something went wrong: {}'.format(e))

client = Client(kwl)
async def run():
    metrics = await client.fetch_metrics([
      'A_CYC_TEMP_EXHAUST_AIR',
      'A_CYC_TEMP_EXTRACT_AIR',
      'A_CYC_TEMP_OUTDOOR_AIR',
      'A_CYC_TEMP_SUPPLY_AIR',
      'A_CYC_TEMP_SUPPLY_CELL_AIR'
    ])

    message = json.dumps(metrics)

    from pprint import pprint
    pprint(message)

    fh = fhem.Fhem("" + web + "", protocol="https", port=8083, username="" + format(credentials["username"]) + "" , password="" + format(credentials["password"]) + "")

    fh.send_cmd("setreading KWL output " + message)

asyncio.get_event_loop().run_until_complete(run())


Die pwd.json Datei ist mit 600nur für den Owner fhem freigegeben.

Und es ist kein Loch gebohrt  ;)

Vielen Dank
    Christian

P.S. Ich hoffe ich war nicht zu schwierig.
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

Wäre es nicht sinnvoll, bei dem major change, wenn das Python 2 raus fliegt dann auch das Modul im Python umzubenennen?
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

domschl

Das ist noch holper-pyhton ;-)

    fh = fhem.Fhem("" + web + "", protocol="https", port=8083, username="" + format(credentials["username"]) + "" , password="" + format(credentials["password"]) + "")


Einfacher:

    fh = fhem.Fhem("" + web + "", protocol="https", port=8083, username=credentials["username"] , password=credentials["password"])


ch.eick

#46
Zitat von: domschl am 21 August 2019, 18:56:46
Das ist noch holper-pyhton ;-)

Ich habe ja heute das erste mal Python gelesen  :'( nicht schimpfen.

schon erledigt

fh = fhem.Fhem(web, protocol="https", port=8083, username=credentials["username"], password=credentials["password"])


Und was ist mit?

fh.send_cmd("setreading KWL output " + message)


Gruß
     Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

domschl

Zum Namen vom Python-Modul, da das ja letztlich doch öfter diskutiert wird:

- Es ist im Python-Land gang und gäbe, daß eine Client-API einfach so wie der Server heißt. Z.b. zugriff auf die Redis-Datenbank geht über "import redis"
- Das gleiche Prinzip wird auch im FHEM verwendet: Viele der Module heissen genauso wie das Produkt/die Software auf die sie zugreifen.

Übersehe ich da was?

domschl

das setreading ist ok: es werden ja nur zwei Strings zusammengebaut.

Da gibt's keinen Grund das komplizierter zu machen.

ch.eick

Zitat von: domschl am 21 August 2019, 19:10:07
Zum Namen vom Python-Modul, da das ja letztlich doch öfter diskutiert wird:

- Es ist im Python-Land gang und gäbe, daß eine Client-API einfach so wie der Server heißt. Z.b. zugriff auf die Redis-Datenbank geht über "import redis"
- Das gleiche Prinzip wird auch im FHEM verwendet: Viele der Module heissen genauso wie das Produkt/die Software auf die sie zugreifen.

Übersehe ich da was?

Wenn das so Python Standard ist, dann würde ich das auch so unterstützen.
Works as designed

Ich hatte nur bisher diese Begründung nirgends gelesen.

Gruß
    Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

Hallo zusammen und entschuldigt bitte, dass ich diesen Post hier wiederhole.
Ich denke hier passt er besser rein.

jetzt versuche ich gerade das Python Skript mit at im FHEM aufzurufen, jedoch scheint die ssl Umgebung unterschiedlich zu sein.


defmod KWL_poll at +*00:05:00 {system("/usr/bin/python /opt/fhem/python/bin/kwl_status.py <IP der KWL> <IP des FHEM Server>")}


Für die Kopplung verwende ich das Python FHEM API-Modul, das bei Aufruf über system() folgende Fehler ausgibt.
In dieser Laufzeitumgebung scheint es ein Problem mit "CSRF token not available!" zu geben.

Failed to send msg, len=0, <urlopen error _ssl.c:704: The handshake operation timed out>
No valid answer on send when expecting csrf.
Failed to send msg, len=0, <urlopen error _ssl.c:704: The handshake operation timed out>
No valid answer on send when expecting csrf.
CSRF token not available!
Failed to send msg, len=185, <urlopen error _ssl.c:704: The handshake operation timed out>
2019.08.22 12:13:54 1: FHEMWEB SSL/HTTPS error:  SSL accept attempt failed (peer: <IP des FHEM Server>)
2019.08.22 12:13:55 1: FHEMWEB SSL/HTTPS error:  SSL accept attempt failed (peer: <IP des FHEM Server>)
2019.08.22 12:13:55 1: FHEMWEB SSL/HTTPS error:  SSL accept attempt failed (peer: <IP des FHEM Server>)


Das gleiche Kommand als user fhem in der unix session läuft tadellos.


import fhem
import json
import asyncio
from vallox_websocket_api import Client

import sys
kwl = sys.argv[1]
web = sys.argv[2]

try:
    with open('/opt/fhem/python/pwd.json', 'r') as f:
        credentials=json.load(f)
except Exception as e:
    print('Something went wrong: {}'.format(e))

client = Client(kwl)
async def run():
#    metrics = await client.fetch_metrics()

    metrics = await client.fetch_metrics([
      'A_CYC_TEMP_EXHAUST_AIR',
      'A_CYC_TEMP_EXTRACT_AIR',
      'A_CYC_TEMP_OUTDOOR_AIR',
      'A_CYC_TEMP_SUPPLY_AIR',
      'A_CYC_TEMP_SUPPLY_CELL_AIR'
    ])

    message = json.dumps(metrics)

#    from pprint import pprint
#    pprint(message)

    fh = fhem.Fhem(web, protocol="https", port=8083, username=credentials["username"], password=credentials["password"])

    fh.send_cmd("setreading KWL output " + message)

asyncio.get_event_loop().run_until_complete(run())



$ ps -ef |grep perl
fhem      8576     1 17 10:18 pts/0    00:22:24 /usr/bin/perl ./fhem.pl ./fhem.cfg


Was muss ich da noch für Zauberworte sprechen, um die HTTPS Umgebung beim "system()" Aufruf zum Laufen zu bekommen?

Gruß
   Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

#51
Moin,

Ihr könntet mir sehr weiterhelfen.
Leider habe ich keine Python Kenntnisse, doch die erste Implementierung ist sehr vielversprechend und ich würde diese Python Fhem Kopplung wirklich gerne verwenden.

Dieser Aufruf als Benutzer fhem in einer Shell funktioniert

DEBUG:Fhem:Setting up opener on: https://<IP Adresse>:8083/
DEBUG:Fhem:Cmd:
DEBUG:Fhem:Cmd-enc:

INFO:Fhem:Request: https://<IP Adresse>:8083/fhem

DEBUG:Fhem:Sending: setreading KWL output {"A_CYC_TEMP_EXHAUST_AIR": 32.3, "A_CYC_TEMP_SUPPLY_AIR": 27.4, "A_CYC_TEMP_EXTRACT_AIR": 26.3, "A_CYC_TEMP_OUTDOOR_AIR": 33.0, "A_CYC_TEMP_SUPPLY_CELL_AIR": 26.1}

DEBUG:Fhem:Cmd: setreading KWL output {"A_CYC_TEMP_EXHAUST_AIR": 32.3, "A_CYC_TEMP_SUPPLY_AIR": 27.4, "A_CYC_TEMP_EXTRACT_AIR": 26.3, "A_CYC_TEMP_OUTDOOR_AIR": 33.0, "A_CYC_TEMP_SUPPLY_CELL_AIR": 26.1}

DEBUG:Fhem:Cmd-enc: setreading%20KWL%20output%20%7B%22A_CYC_TEMP_EXHAUST_AIR%22%3A%2032.3%2C%20%22A_CYC_TEMP_SUPPLY_AIR%22%3A%2027.4%2C%20%22A_CYC_TEMP_EXTRACT_AIR%22%3A%2026.3%2C%20%22A_CYC_TEMP_OUTDOOR_AIR%22%3A%2033.0%2C%20%22A_CYC_TEMP_SUPPLY_CELL_AIR%22%3A%2026.1%7D

INFO:Fhem:Request: https://<IP Adresse>:8083/fhem?XHR=1&cmd=setreading%20KWL%20output%20%7B%22A_CYC_TEMP_EXHAUST_AIR%22%3A%2032.3%2C%20%22A_CYC_TEMP_SUPPLY_AIR%22%3A%2027.4%2C%20%22A_CYC_TEMP_EXTRACT_AIR%22%3A%2026.3%2C%20%22A_CYC_TEMP_OUTDOOR_AIR%22%3A%2033.0%2C%20%22A_CYC_TEMP_SUPPLY_CELL_AIR%22%3A%2026.1%7D


Und so sieht der Debug mit dem Aufruf über ein FHEM Notify aus.

defmod KWL_poll at +*01:00:00 {system("/usr/bin/python /opt/fhem/python/bin/kwl_status.py <IP kwl> <IP FHEM>")}


DEBUG:Fhem:Setting up opener on: https://<IP FHEM>:8083/
DEBUG:Fhem:Cmd:
DEBUG:Fhem:Cmd-enc:

INFO:Fhem:Request: https://<IP FHEM>:8083/fhem

ERROR:Fhem:Failed to send msg, len=0, <urlopen error _ssl.c:704: The handshake operation timed out>
ERROR:Fhem:No valid answer on send when expecting csrf.

DEBUG:Fhem:Sending: setreading KWL output {"A_CYC_TEMP_EXTRACT_AIR": 26.5, "A_CYC_TEMP_SUPPLY_AIR": 27.7, "A_CYC_TEMP_SUPPLY_CELL_AIR": 26.2, "A_CYC_TEMP_EXHAUST_AIR": 32.5, "A_CYC_TEMP_OUTDOOR_AIR": 33.0}
DEBUG:Fhem:Not connected, trying to connect...
DEBUG:Fhem:Cmd:
DEBUG:Fhem:Cmd-enc:

INFO:Fhem:Request: https://<IP FHEM>:8083/fhem

ERROR:Fhem:Failed to send msg, len=0, <urlopen error _ssl.c:704: The handshake operation timed out>
ERROR:Fhem:No valid answer on send when expecting csrf.
ERROR:Fhem:CSRF token not available!

DEBUG:Fhem:Cmd: setreading KWL output {"A_CYC_TEMP_EXTRACT_AIR": 26.5, "A_CYC_TEMP_SUPPLY_AIR": 27.7, "A_CYC_TEMP_SUPPLY_CELL_AIR": 26.2, "A_CYC_TEMP_EXHAUST_AIR": 32.5, "A_CYC_TEMP_OUTDOOR_AIR": 33.0}

DEBUG:Fhem:Cmd-enc: setreading%20KWL%20output%20%7B%22A_CYC_TEMP_EXTRACT_AIR%22%3A%2026.5%2C%20%22A_CYC_TEMP_SUPPLY_AIR%22%3A%2027.7%2C%20%22A_CYC_TEMP_SUPPLY_CELL_AIR%22%3A%2026.2%2C%20%22A_CYC_TEMP_EXHAUST_AIR%22%3A%2032.5%2C%20%22A_CYC_TEMP_OUTDOOR_AIR%22%3A%2033.0%7D

INFO:Fhem:Request: https://<IP FHEM>:8083/fhem?XHR=1&cmd=setreading%20KWL%20output%20%7B%22A_CYC_TEMP_EXTRACT_AIR%22%3A%2026.5%2C%20%22A_CYC_TEMP_SUPPLY_AIR%22%3A%2027.7%2C%20%22A_CYC_TEMP_SUPPLY_CELL_AIR%22%3A%2026.2%2C%20%22A_CYC_TEMP_EXHAUST_AIR%22%3A%2032.5%2C%20%22A_CYC_TEMP_OUTDOOR_AIR%22%3A%2033.0%7D
ERROR:Fhem:Failed to send msg, len=185, <urlopen error _ssl.c:704: The handshake operation timed out>


Viele Grüße
    Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

Und noch ein Status :-)

Ich habe nun bei dem system() Aufruf das Kommando mit "&" in den Hintergrung geschickt.
Eventuell kann mir ja jemand jetzt erklären, warum es nun läuft???

defmod KWL_poll at +*01:00:00 {system("/usr/bin/python /opt/fhem/python/bin/kwl_status.py <IP KWL> <IP FHEM> &")}


Bei system(... &) läuft die https Verbindung vom Python zum FHEM nun.

DEBUG:Fhem:Setting up opener on: https://<IP FHEM>:8083/
DEBUG:Fhem:Cmd:
DEBUG:Fhem:Cmd-enc:

INFO:Fhem:Request: https://<IP FHEM>:8083/fhem

DEBUG:Fhem:Sending: setreading KWL output {"A_CYC_TEMP_SUPPLY_AIR": 27.6, "A_CYC_TEMP_SUPPLY_CELL_AIR": 26.1, "A_CYC_TEMP_EXTRACT_AIR": 26.4, "A_CYC_TEMP_EXHAUST_AIR": 32.0, "A_CYC_TEMP_OUTDOOR_AIR": 32.5}

DEBUG:Fhem:Cmd: setreading KWL output {"A_CYC_TEMP_SUPPLY_AIR": 27.6, "A_CYC_TEMP_SUPPLY_CELL_AIR": 26.1, "A_CYC_TEMP_EXTRACT_AIR": 26.4, "A_CYC_TEMP_EXHAUST_AIR": 32.0, "A_CYC_TEMP_OUTDOOR_AIR": 32.5}

DEBUG:Fhem:Cmd-enc: setreading%20KWL%20output%20%7B%22A_CYC_TEMP_SUPPLY_AIR%22%3A%2027.6%2C%20%22A_CYC_TEMP_SUPPLY_CELL_AIR%22%3A%2026.1%2C%20%22A_CYC_TEMP_EXTRACT_AIR%22%3A%2026.4%2C%20%22A_CYC_TEMP_EXHAUST_AIR%22%3A%2032.0%2C%20%22A_CYC_TEMP_OUTDOOR_AIR%22%3A%2032.5%7D

INFO:Fhem:Request: https://<IP FHEM>:8083/fhem?XHR=1&cmd=setreading%20KWL%20output%20%7B%22A_CYC_TEMP_SUPPLY_AIR%22%3A%2027.6%2C%20%22A_CYC_TEMP_SUPPLY_CELL_AIR%22%3A%2026.1%2C%20%22A_CYC_TEMP_EXTRACT_AIR%22%3A%2026.4%2C%20%22A_CYC_TEMP_EXHAUST_AIR%22%3A%2032.0%2C%20%22A_CYC_TEMP_OUTDOOR_AIR%22%3A%2032.5%7D


Viele Grüße
    Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

domschl

Release 0.6.3 ist nun auf PyPi verfügbar.

Bugfixes:
* Bug von @TK67 bzgl. Exception Meldungen bei Socket-Verbindungen sollte gelöst sein,
* Bug von party-pansen bzgl. crashes bei ungesichertem parsen von FhemEventQueue datetimes gelöst,
* Der Selbst-Test checked jetzt auf die FhemEventQueue Klasse.

Details zu den Versionen und fixes https://github.com/domschl/python-fhem#history
Update wie immer mit:

pip install -U fhem

ROMASI

Hallo, ich dreh am Rad
Erst mal Danke für die Tolle Anleitung zum Einbinden des Vallox-Lüfters Konkret habe ich einen Vallox mv520. Auf der Shell Ebene funktionieren deine py-scripte auch prima, aber wenn ich das aus FHEM heraus aufrufe bekomme ich den gleichen Fehler wie bei dir hier im Thread kurz zuvor beschrieben:
2019.10.30 11:01:56 1: KWL Profil geändert
Traceback (most recent call last):
  File "/opt/fhem/python/bin/kwl_set_profil.py", line 8, in <module>
    from vallox_websocket_api import Vallox, PROFILE
ImportError: No module named 'vallox_websocket_api'


Wenn ich kwl_status.py aus FHEM heraus aufgerufen wird erscheint der gleiche Fehler jedoch mit der FHEM-API
ImportError: No module named 'fhem'


Ich rufe die Scripte auf mit:
{system("/usr/bin/python3.5 /opt/fhem/python/bin/kwl_set_profil.py IPKWS.x.x.x IP-Fehm.x.x.x &")}

Das API Python Paket habe ich installiert mit:
sudo pip3 install vallox_websocket_api
sudo pip3 install fhem


Wie gesagt über den Shell-Auftuf mit dem User Pi funktioniert alles.
Die Py-Scripts stehen auch wie in deinem Beispiel unter /opt/fhem/python/bin

Ich konnte aus dem weiteren Verlauf der Antworten hier im Forum aber nicht ersehen wie du den Fehler weg bekommen hast.

Eventuell kann mir hier jemand auf die Sprünge helfen.

Viele Grüße
Ronald


ch.eick

#55
Hallo Ronald,

ich habe bei mir die Installation genau so wie beschrieben vorgenommen.

fhem@raspberrypi:~$ python --version
Python 3.5.3

Wie man im Python die installierte Version der Module abfragt habe ich noch nicht gefunden. Ich kenne mich mit Python nicht aus.
Ich bin nur in der Lage die verstreuten Codemuster zu kombinieren :-)
Hier nochmal eins meiner aktuellen Skripte. Am Anfang sind für das Debugging zwei Zeilen auskommentiert, das könntest Du ja mal einschalten und die Meldungen verfolgen. Zum Ende des Skriptes sind auch noch zwei print Ausgaben, damit man auf der Shell die gelesenen Werte sehen kann.

fhem@raspberrypi:~/python/bin$ cat kwl_status.py
# import logging
# logging.basicConfig(level=logging.DEBUG)

import fhem
import json
import asyncio
from vallox_websocket_api import Client

import sys
kwl = sys.argv[1]
web = sys.argv[2]

try:
    with open('/opt/fhem/python/pwd.json', 'r') as f:
        credentials=json.load(f)
except Exception as e:
    print('Something went wrong: {}'.format(e))

client = Client(kwl)
async def run():
#    metrics = await client.fetch_metrics()

    metrics = await client.fetch_metrics([
      'A_CYC_TEMP_EXHAUST_AIR',
      'A_CYC_TEMP_EXTRACT_AIR',
      'A_CYC_TEMP_OUTDOOR_AIR',
      'A_CYC_TEMP_SUPPLY_AIR',
      'A_CYC_TEMP_SUPPLY_CELL_AIR',
      'A_CYC_MODE',
      'A_CYC_STATE',
      'A_CYC_FAN_SPEED',
      'A_CYC_CELL_STATE',
      'A_CYC_IN_BYPASS',
      'A_CYC_MACHINE_MODEL',
      'A_CYC_DAY',
      'A_CYC_MONTH',
      'A_CYC_YEAR',
      'A_CYC_HOUR',
      'A_CYC_MINUTE',
      'A_CYC_MACHINE_MODEL',
      'A_CYC_MACHINE_TYPE',
      'A_CYC_FILTER_CHANGED_DAY',
      'A_CYC_FILTER_CHANGED_MONTH',
      'A_CYC_FILTER_CHANGED_YEAR',
      'A_CYC_REMAINING_TIME_FOR_FILTER',
      'A_CYC_BOOST_TIMER',
      'A_CYC_FIREPLACE_TIMER',
      'A_CYC_EXTRA_TIMER',
      'A_CYC_EXTRA_TIMER_ENABLED',
      'A_CYC_EXTRA_ENABLED',
      'A_CYC_EXTRA_EXTR_FAN',
      'A_CYC_EXTRA_SUPP_FAN'
    ])

    message = json.dumps(metrics)
   
    from pprint import pprint
#    pprint(message)
#    pprint(metrics)

    fh = fhem.Fhem(web, protocol="https", port=8083, username=credentials["username"], password=credentials["password"])

    fh.send_cmd("setreading KWL_Status output " + message)

asyncio.get_event_loop().run_until_complete(run())


Die Module habe ich auch mit dem user pi installiert.
Ich meine es war auch wichtig in welche Pythen Version man die Module installiert. Deshalb habe ich das Python unter /usr/bin direkt auf Version python3 verlinkt

pi@raspberrypi:~ $ cd /usr/bin

# sudo rm python
# sudo ln -s python3 python

pi@raspberrypi:/usr/bin $ ls -l python*
lrwxrwxrwx 1 root root       7 Aug 22 11:19 python -> python3
lrwxrwxrwx 1 root root       9 Jan 24  2017 python2 -> python2.7
-rwxr-xr-x 1 root root 3166320 Sep 26  2018 python2.7
lrwxrwxrwx 1 root root      36 Sep 26  2018 python2.7-config -> arm-linux-gnueabihf-python2.7-config
lrwxrwxrwx 1 root root      16 Jan 24  2017 python2-config -> python2.7-config
lrwxrwxrwx 1 root root       9 Jan 20  2017 python3 -> python3.5
-rwxr-xr-x 2 root root 3976256 Sep 27  2018 python3.5
lrwxrwxrwx 1 root root      36 Sep 27  2018 python3.5-config -> arm-linux-gnueabihf-python3.5-config
-rwxr-xr-x 2 root root 3976256 Sep 27  2018 python3.5m
lrwxrwxrwx 1 root root      37 Sep 27  2018 python3.5m-config -> arm-linux-gnueabihf-python3.5m-config
lrwxrwxrwx 1 root root      16 Jan 20  2017 python3-config -> python3.5-config
lrwxrwxrwx 1 root root      10 Jan 20  2017 python3m -> python3.5m
lrwxrwxrwx 1 root root      17 Jan 20  2017 python3m-config -> python3.5m-config
lrwxrwxrwx 1 root root      16 Jan 24  2017 python-config -> python2.7-config


EDIT:
Und so kann man die Modulversion überprüfen:

fhem@raspberrypi:~$ python
Python 3.5.3 (default, Sep 27 2018, 17:25:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import fhem
>>> fhem.__version__
'0.6.3'

################################### Hier scheint keine Version eingetragen zu sein, aber zumindest wird es gefunden. ###########
>>> import vallox_websocket_api
>>> vallox_websocket_api.__version__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'vallox_websocket_api' has no attribute '__version__'



Gruß
    Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ROMASI

Hallo Christian
Vielen Dank für deine schnelle Antwort, ich beschäftige mich nun schon einige Zeit mit dem Problem und nach Lesen in etlichen Foren und Python Beschreibungen konnte ich das Problem:
"Nicht Laden der python import Module aus Fhem heraus"
lösen.
Dein Vorschlag auf Python3 als Standardversion umzustellen ist bei mir leider fehlgeschlagen. Ich habe auch mehrfach gelesen, dass diese Umstellung auf dem Raspi nicht empfohlen wird. Daher installiere ich die API-Pakete mit pip3 anstatt mit pip. Dein Python-skript starte ich aus Fhem heraus dann mit:
({system("/usr/bin/python3 /opt/fhem/python/bin/kwl_set_profil.py ....
Meinen eigentlichen Fehler konnte ich mit dem Befehl
pip3 show fhem
feststellen.  Da ich die API-Pakete mit pip3 ohne 'sudo' installiert hatte waren die Module nur für dem 'pi' User verfügbar und nicht aus Fhem heraus!
Richtig muss es heisen:
sudo pip3 install fhen
sudo pip3 install vallox-websocket-api

Dann sind die Pakete unter /usr/local/iib/... für alle User verfügbar
Was man dann wie dargestellt kontrollieren kann:
pi@fhem-sh-si:~ $ pip3 show fhem
Name: fhem
Version: 0.6.3
Summary: Python API for FHEM home automation server
Home-page: http://github.com/domschl/python-fhem
Author: Dominik Schloesser
Author-email: dsc@dosc.net
License: MIT
Location: /usr/local/lib/python3.5/dist-packages
Requires:
pi@fhem-sh-si:~ $


Jetzt funktioniert alles prima und ich kann die Vallox Lüftung dank deiner Skripts aus Fhem heraus steuern und auslesen.

Viele Grüße
Ronald

ch.eick

#57
Super, das freut mich.
Wie gesagt habe ich nur Beispiele kombiniert. Den Code haben andere geschrieben.

kwl_set_profile.py

fhem@raspberrypi:~/python/bin$ cat kwl_set_profil.py
# import logging
# logging.basicConfig(level=logging.DEBUG)

import fhem
import json
import asyncio
from vallox_websocket_api import Vallox, PROFILE

import sys
kwl     = sys.argv[1]
web     = sys.argv[2]
profile = sys.argv[3]

try:
    with open('/opt/fhem/python/pwd.json', 'r') as f:
        credentials=json.load(f)
except Exception as e:
    print('Something went wrong: {}'.format(e))

client = Vallox(kwl) # Vallox unit IP

async def run():
    await client.get_profile() # RETURNS a PROFILE.* value

    if profile == "1":
         await client.set_profile(PROFILE.HOME)      # Permanently HOME profile
    elif profile == "2":
         await client.set_profile(PROFILE.AWAY)      # Permanently AWAY profile
    elif profile == "3":
         await client.set_profile(PROFILE.BOOST)     # BOOST profile for configured time ( 30 minutes )
    elif profile == "4":
         await client.set_profile(PROFILE.FIREPLACE) # FIREPLACE mode for configured timeout
    elif profile == "5":
         await client.set_profile(PROFILE.EXTRA)     # EXTRA mode for configured timeout
    else:
         await client.set_profile(PROFILE.AWAY)      # Permanently AWAY profile


    fh = fhem.Fhem(web, protocol="https", port=8083, username=credentials["username"], password=credentials["password"])

    fh.send_cmd("set KWL_Call cmd_2")

asyncio.get_event_loop().run_until_complete(run())


kwl_status.py

fhem@raspberrypi:~/python/bin$ cat kwl_status.py
# import logging
# logging.basicConfig(level=logging.DEBUG)

import fhem
import json
import asyncio
from vallox_websocket_api import Client

import sys
kwl = sys.argv[1]
web = sys.argv[2]

try:
    with open('/opt/fhem/python/pwd.json', 'r') as f:
        credentials=json.load(f)
except Exception as e:
    print('Something went wrong: {}'.format(e))

client = Client(kwl)
async def run():
#    metrics = await client.fetch_metrics()

    metrics = await client.fetch_metrics([
      'A_CYC_TEMP_EXHAUST_AIR',
      'A_CYC_TEMP_EXTRACT_AIR',
      'A_CYC_TEMP_OUTDOOR_AIR',
      'A_CYC_TEMP_SUPPLY_AIR',
      'A_CYC_TEMP_SUPPLY_CELL_AIR',
      'A_CYC_MODE',
      'A_CYC_STATE',
      'A_CYC_FAN_SPEED',
      'A_CYC_CELL_STATE',
      'A_CYC_IN_BYPASS',
      'A_CYC_MACHINE_MODEL',
      'A_CYC_DAY',
      'A_CYC_MONTH',
      'A_CYC_YEAR',
      'A_CYC_HOUR',
      'A_CYC_MINUTE',
      'A_CYC_MACHINE_MODEL',
      'A_CYC_MACHINE_TYPE',
      'A_CYC_FILTER_CHANGED_DAY',
      'A_CYC_FILTER_CHANGED_MONTH',
      'A_CYC_FILTER_CHANGED_YEAR',
      'A_CYC_REMAINING_TIME_FOR_FILTER',
      'A_CYC_BOOST_TIMER',
      'A_CYC_FIREPLACE_TIMER',
      'A_CYC_EXTRA_TIMER',
      'A_CYC_EXTRA_TIMER_ENABLED',
      'A_CYC_EXTRA_ENABLED',
      'A_CYC_EXTRA_EXTR_FAN',
      'A_CYC_EXTRA_SUPP_FAN'
    ])

    message = json.dumps(metrics)
   
    from pprint import pprint
#    pprint(message)
#    pprint(metrics)

    fh = fhem.Fhem(web, protocol="https", port=8083, username=credentials["username"], password=credentials["password"])

    fh.send_cmd("setreading KWL_Status output " + message)

asyncio.get_event_loop().run_until_complete(run())




Und hier die FHEM Integration

Diese Dummy representiert die KWL mit ihrem Status und dem Profil
Über einen Slider kann das Profil von 1-5 eingestellt werden.
Bei mit ist in der Vallox KWL das Profiel Stoßlüften mit 70% konfiguriert.
Mit dem EXTRA Profil habe ich dann die Möglichkeit für eine konfigurierte Zeit von 10 Minuten auf 100% Lüfter zu schalten. Das EXTRA Profil lässt sich nicht über das WEB Interface der Vallox konfigurieren, jedoch kann das mit einem Python Skript und dem Setzen der entsprechenden Register erledigt werden. Das Skript kommt am Ende dieses Posts.

defmod KWL_Control dummy
attr KWL_Control alias KWL_Control
attr KWL_Control comment Profile \
1=Anwesend/Home,\
2=Abwesend/Away,\
3=Stosslueften/Boost,\
4=Kaminfunktion/Fireplace\
5=Extra
attr KWL_Control group KWL
attr KWL_Control icon audio_eq
attr KWL_Control readingList Profil
attr KWL_Control room Heizung->System
attr KWL_Control setList Profil:slider,1,1,5
attr KWL_Control sortby 01
attr KWL_Control stateFormat {sprintf("innen %d °C, Zuluft %d °C, Abluf %d °C, außen %d °C | %s %s| %s", \
ReadingsVal("KWL_Status","A_CYC_TEMP_EXTRACT_AIR","?"),\
ReadingsVal("KWL_Status","A_CYC_TEMP_SUPPLY_AIR","?"),\
ReadingsVal("KWL_Status","A_CYC_TEMP_EXHAUST_AIR","?"),\
ReadingsVal("KWL_Status","A_CYC_TEMP_OUTDOOR_AIR","?"),\
ReadingsVal("KWL_Status","EXT_CYC_STATE","?"),\
ReadingsVal("KWL_Status","EXT_CYC_CELL_STATE","?"),\
ReadingsVal("KWL_Status","EXT_CYC_TIME","?")\
)}


Hier wird der Status der KWL aufbereitet und das Profil aus verschiedenen Variablen ermittelt

defmod KWL_Status expandJSON KWL_Status:output:.\{.*}
attr KWL_Status alias KWL_Status
attr KWL_Status comment Das Device wird über ein Python Skript im reading output befüllt.\
deletereading KWL [A|C|EXT|RANGE|WS].*\
CYC_CELL_STATE 0=WRG, 1= KRG, 2= Bypass, 3=Defrost\
CYC_STATE 0=HOME, 1=AWAY
attr KWL_Status group KWL
attr KWL_Status icon Ventilator_wind
attr KWL_Status room Heizung->System
attr KWL_Status sortby 02
attr KWL_Status userReadings EXT_CYC_TIME { sprintf("%0.2i:%0.2i",ReadingsVal("$name","A_CYC_HOUR",""), ReadingsVal("$name","A_CYC_MINUTE","")) } ,\
EXT_CYC_DATE { sprintf("20%i.%0.2i.%0.2i",ReadingsVal("$name","A_CYC_YEAR",""), ReadingsVal("$name","A_CYC_MONTH",""), ReadingsVal("$name","A_CYC_DAY","")) } ,\
EXT_CYC_FILTER_CHANGED_DATE { sprintf("20%i.%0.2i.%0.2i",ReadingsVal("$name","A_CYC_FILTER_CHANGED_YEAR",""), ReadingsVal("$name","A_CYC_FILTER_CHANGED_MONTH",""), ReadingsVal("$name","A_CYC_FILTER_CHANGED_DAY","") ) },\
EXT_CYC_STATE {\
if     (ReadingsVal("$name","A_CYC_BOOST_TIMER","?") > 0 ) {sprintf("%s", "Boost")}\
elsif (ReadingsVal("$name","A_CYC_FIREPLACE_TIMER","?") > 0 ) {sprintf("%s", "Fireplace")}\
elsif (ReadingsVal("$name","A_CYC_EXTRA_TIMER","?") > 0 ) {sprintf("%s", "Extra")}\
elsif (ReadingsVal("$name","A_CYC_STATE","?") == 0 ) {sprintf("%s", "Home")}\
else  {sprintf("%s", "Away")}\
}, \
EXT_CYC_CELL_STATE {\
if     (ReadingsVal("$name","A_CYC_CELL_STATE","?") == 0 ) {sprintf("%s", "WRG")}\
elsif (ReadingsVal("$name","A_CYC_CELL_STATE","?") == 1 ) {sprintf("%s", "KRG")}\
elsif (ReadingsVal("$name","A_CYC_CELL_STATE","?") == 2 ) {sprintf("%s", "Bypass")}\
elsif (ReadingsVal("$name","A_CYC_CELL_STATE","?") == 3 ) {sprintf("%s", "Defrost")}\
else  {sprintf("%s", "?")}\
}


Das DOIF erledigt das Polling und die Kommunikation bei Änderungen wenn ein anderes Profil eingestellt wird.

defmod KWL_Call DOIF ##\
## Ändert sich in KWL_Control das Profil, dann sende es zur KWL\
##\
([KWL_Control:Profil])\
    ({system("/usr/bin/python /opt/fhem/python/bin/kwl_set_profil.py ".ReadingsVal("KWL_Control","KWL_Ip-Adress","?")." ".ReadingsVal("KWL_Control","FHEM_Ip-Adress","?")." ".ReadingsVal("KWL_Control","Profil","?")." &")}\
     {fhem("setreading KWL_Control KWL_next_polling ".ReadingsVal("KWL_Call","timer_01_c02","?"))}\
     {fhem("setreading KWL_Status KWL_next_polling ".ReadingsVal("KWL_Call","timer_01_c02","?"))}\
     {Log 1, "KWL Profil geändert"})\
##\
## Abfrage der KWL in 5 Minuten Intervallen\
##\
DOELSEIF ([+00:05:00])\
     {system("/usr/bin/python /opt/fhem/python/bin/kwl_status.py ".ReadingsVal("KWL_Control","KWL_Ip-Adress","?")." ".ReadingsVal("KWL_Control","FHEM_Ip-Adress","?")." &")}\
     {Log 1, "KWL polling"}\
##\
## Publiziere den Intervall Timer\
##\
DOELSEIF ([KWL_Status:EXT_CYC_TIME])\
     {fhem("setreading KWL_Control KWL_next_polling ".ReadingsVal("KWL_Call","timer_01_c02","?"))}\
     {fhem("setreading KWL_Status KWL_next_polling ".ReadingsVal("KWL_Call","timer_01_c02","?"))}\
     {Log 1, "KWL new intervall"}
attr KWL_Call alias KWL_Call
attr KWL_Call checkReadingEvent 1
attr KWL_Call cmdState Profil geändert|KWL polling|KWL polling finished
attr KWL_Call do always
attr KWL_Call group KWL
attr KWL_Call icon file_manpage
attr KWL_Call room Heizung->System
attr KWL_Call sortby 04
attr KWL_Call verbose 0


Hier das angekündigte Skript zum setzen des EXTRA Profils. Die Werte für die Lüfter und die Zeit kann jeder auf seine extra Wünsche einstellen :-)

fhem@raspberrypi:~/python/bin$ cat kwl_set_extra.py
# import logging
# logging.basicConfig(level=logging.DEBUG)

import fhem
import json
import asyncio
from vallox_websocket_api import Vallox, PROFILE

import sys
kwl     = sys.argv[1]

try:
    with open('/opt/fhem/python/pwd.json', 'r') as f:
        credentials=json.load(f)
except Exception as e:
    print('Something went wrong: {}'.format(e))

client = Vallox(kwl) # Vallox unit IP

async def run():
    await client.get_profile() # RETURNS a PROFILE.* value

    client.set_settable_address('A_CYC_EXTRA_ENABLED', int)
    client.set_settable_address('A_CYC_EXTRA_TIMER_ENABLED', int)

    # Setting Extra profile
    await client.set_values({
      'A_CYC_EXTRA_ENABLED': 1,
      'A_CYC_EXTRA_EXTR_FAN': 100,
      'A_CYC_EXTRA_SUPP_FAN': 100,
      'A_CYC_EXTRA_TIMER': 10,
      'A_CYC_EXTRA_TIMER_ENABLED': 1
      })

asyncio.get_event_loop().run_until_complete(run())




Gruß Christian

RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Forstling

Hallo

bei mir scheitert derzeit auch der Aufruf aus FHEM

Ich möchte einen PT1000 Temperaturfühler auslesen. Das funktioniert über einen MAX31865 Chip

Das Script kann ich ausführen und die Werte kommen auch bei FHEM an.

Wenn ich das Script über FHEM Aufrufe Schreibt es mir folgendes in Log:

Traceback (most recent call last):
  File "/opt/fhem/FHEM/Python/MAX31865.py", line 33, in <module>
    sensor = adafruit_max31865.MAX31865(spi, cs, wires=4)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_max31865.py", line 107, in __init__
    config = self._read_u8(_MAX31865_CONFIG_REG)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_max31865.py", line 123, in _read_u8
    device.write(self._BUFFER, end=1)
  File "/usr/local/lib/python3.7/dist-packages/busio.py", line 203, in write
    return self._spi.write(buf, start, end)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_blinka/microcontroller/generic_linux/spi.py", line 49, in write
    self._spi.open(self._port, 0)
PermissionError: [Errno 13] Permission denied


Ich nehme an das ich hier ein Rechteproblem habe:

Kann mir jemand sagen wie ich das Löseß

amenomade

Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

Forstling

#60
pi@raspberrypi:~ $ ls -la /opt/fhem/FHEM/Python
insgesamt 52
drwxr-xr-x 2 pi   pi       4096 Feb  2 19:15 .
drwxrwxrwx 7 fhem dialout 36864 Feb  2 19:10 ..
-rwxr-xr-x 1 pi   pi       2147 Feb  2 19:58 fhem-dht.py
-rwxrwxrwx 1 pi   pi       1914 Feb  2 20:49 MAX31865.py
pi@raspberrypi:~ $

?

fhem-dht.py funktioniert

amenomade

Zitat von: Forstling am 02 Februar 2020, 21:13:30

fhem-dht.py funktioniert
Ja, aber der User fhem darf es nicht ausführen.
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

Forstling

Jetzt funktioniert es

es Lag daran das FHEM nicht auf den SPI Bus zugreifen durfte.



Gear

#63
Guten Morgen Zusammen!

Ich habe das Problem, dass manchmal beim Auslesen nur ein "{}" ausgelesen wird.
Mein Script funktioniert ohne Probleme, die Verbindung wird als "true" zurückgegeben.

Hat jemand eine Idee?

Edit:
Ich habe nun mal zum Testen ein TimeOut von 1s auch beim Einlesen gemacht, bis jetzt scheinbar kein Problem mehr...
> ODroid H3 => OMV => Docker => FHEM <
Fritz!Box 7590, Fritz!Repeater 6000, MQTT, RaspberryMatic, Zigbee2MQTT, ESP32, ESP8266, Shelly, Grafana ...
> 3D-Druck <

Gear

So, muss mich mal zurückmelden, wegen dem im vorherigen Problem.
Leider gibt es immer mal wieder Probleme beim Auslesen.

Es wird einfach ein {} zurückgegeben, obwohl das Device einen Wert drin hat.

Es scheint, als würde hier FHEM irgendwie blockiert sein?!
Ich hoffe, dass mir jemand helfen kann.
> ODroid H3 => OMV => Docker => FHEM <
Fritz!Box 7590, Fritz!Repeater 6000, MQTT, RaspberryMatic, Zigbee2MQTT, ESP32, ESP8266, Shelly, Grafana ...
> 3D-Druck <

andies

Vielen Dank für das Modul - ich melde mich wegen eines Problems, das oben auch schon angesprochen wurde. Auch bei mir kommt es manchmal vor, dass beim Auslesen eines Readings {} zurückgegeben wird (ich bekomme dann einen KeyError). Der Fehler tritt unsystematisch auf, so dass ich einen Programmierfehler ausschließe.

Ich kann den Fehler abfangen bzw erhöhe dann die Readingwerte in FHEM. Dennoch würde mich interessieren, wie man dem Problem auf dem Grund gehen kann? Innerhalb von FHEM gelingt mir das nicht.

Hier mein gesamter Code, nur "gas" ist wichtig:

#!/usr/bin/env python3
import time
import sys
import spidev
import RPi.GPIO as GPIO
import fhem


fh = fhem.Fhem("raspfhem.fritz.box")

spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 40000
numdata = 100

# RPi.GPIO Layout verwenden (wie Pin-Nummern)
GPIO.setmode(GPIO.BCM)
# Pin 17 auf Input setzen, dort ist der keyence angeschlossen
GPIO.setup(17, GPIO.IN)

def GetADC():
        Msum = 0
        s = 0
        while s < numdata:
            adc = spi.xfer2([0, 0])
            hi = (adc[0] & 0x1F);
            low = (adc[1] & 0xFE);  # FE for B, FC for C chip (MCP3201-B/C) Danil
            data = (hi << 8) | low;
            Msum += int(data)
            s += 1
        return int(Msum/(4*numdata))

def Gaszaehler():
   try:
      ## Die Fassung hat das Risiko, dass mir zu viel KeyError-Fehler auftauchen, daher wird *in* FHEM erhöht#####
      #gas = fh.get_device_reading("Heizungskeller", "gas")    <=== ausgeblendete Version, weil problematisch
      #i = int(gas["Value"])
      #fh.send_cmd("setreading Heizungskeller gas " + str(i+1))

      fh.send_cmd("setreading Heizungskeller gas {(ReadingsVal(\"Heizungskeller\", \"gas\", 0)+1)}") <== so mache ich das jetzt
     
   except IOError as err:
      fh.send_cmd("setreading Heizungskeller Fehler I/O error: {0} " + str(format(err)))
   #except KeyError:
   #  fh.send_cmd("setreading Heizungskeller Fehler KeyError: Reading gas unlesbar " + str(gas))  <== dieser Fehler taucht nur selten, aber zu oft auf
   except:
      fh.send_cmd("setreading Heizungskeller Fehler Unbekannter Fehler: " + str(sys.exc_info()[0]))
      fh.send_cmd("set TelegramBot message ‼️ Heizungskeller Unbekannter Fehler: " + str(sys.exc_info()[0]))
      raise
   return

zaehlerwasser = 0
WasHigh = False

try:
    while True:
        time.sleep(0.07)
        zaehlerwasser += 1
        if (zaehlerwasser == 4500):
            wasser = GetADC()
            wasser = 25*(wasser // 25)
            fh.send_cmd("setreading Heizungskeller wasser " + str(wasser))
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

domschl

Ich würde zunächst vorschlagen, logging zu aktivieren, s. Beispiel:

https://github.com/domschl/python-fhem#set-and-get-transactions


Also:


import logging
import fhem

logging.basicConfig(level=logging.DEBUG)


domschl

Neue Version 0.7.0 auf PyPi.

Neuigkeiten:

- Support für mehrere Sessions parallel zu einem oder mehreren FHEM Servern.
- Automatische Tests für Python 3.8, 3.10, 3.11
- Kein Support für Python 2 mehr (Version 0.6.5 benutzen!)

Update der neuen python-fhem Version mit:

pip install -U fhem