fhem.js - websocket connection to fhem via node.js proxy

Begonnen von Werner Schäffer, 13 Februar 2015, 21:53:55

Vorheriges Thema - Nächstes Thema

Werner Schäffer

ups, da ist ja einiges aufgelaufen. Ich hatte mich schon gewundert dass keine Einträge hier gemeldet wurden, habe mich aber dann nicht weiter darum gekümmert. Offensichtlich funktioniert aber die E-Mail-Benachrichtung über neue Einträge nicht mehr. Muss mal nachschauen, auch im Spam-Ordner. Ich werd nach und nach die letzten Beiträge beantworten.

peterk_de

Oh hi Werner, meine Anfrage hat sich schon erledigt, ich habe inzwischen eine eigenständige FHEM-Library für node.js umgesetzt (fhem.js war da nicht ganz passend zu). Falls die jemand benötigt, findest du sie hier: https://forum.fhem.de/index.php/topic,72643.msg666190.html#msg666190 als Teil eines kleinen Moduls zur Ansteuerung eines Tastenfeldes mit LCDs hinter den Tasten.
FHEM auf Ubuntu-VM / 2xNUC Proxmox Cluster
UI: HomeKit, TabletUI, Grafana
IOdevs: 2xHueBridge, RaspiMatic-CCU, CUL868, 2xHarmonyHub, 6xRaspi-Roomnode mit CO2, VOC und lepresenced
Devices: 107xHomematic(IP), 96xPhilips Hue, 17xTECHEM, 12xBTLE, 8xSONOS, 2xHomeConnect, 1xShelly 3em, 1xNanoleaf ...

Werner Schäffer

#152
Es gibt im npm-Repository eine neue Version 2.5.12 von fhem.js. Sie kann installiert werden wie üblich mit

npm -g install fhem.js

Zwei Probleme, die in diesem Forumsthread schon aufgetaucht sind, wurden damit gelöst:

  • es gab den Hinweis doch ..../postinstall zu starten. Richtig ist jedoch dass ..../postinstall.sh zu starten ist. Dies wird nun im Hinweis korrekt angezeigt.

  • fhem.js benötigt einen pid File für die Steuerung im Verzeichnis /run/fhem, wobei die Installationsroutine dieses Verzeichnis bisher auch anlegt hat. Das reicht aber nicht, da alle Unterverzeichnisse von /run nach einem Neustart des Rechners erst mal leer sind und sie nur durch Konfigurationseinträge in /usr/lib/tmpfiles.d/ erzeugt werden. Dieser Eintrag wird nun durch das Script postinstall.sh erzeugt. (qubit hat hier in diesem Thread dies schon erläutert - danke)

Tazz

#153
Zitat von: Depechem am 19 Januar 2017, 11:24:50
Nach:  kommt keine Fehlermedung


nach  kommt
1 S fhem       727     1  8  80   0 - 18518 poll_s Jan18 ?        01:31:40 perl fhem.pl fhem.cfg
sozusagen ist der Benutzer "fhem" oder!?

nach  kommt
sudo npm install --unsafe-perm -g fhem.js
/usr/local/bin/forever -> /usr/local/lib/node_modules/fhem.js/node_modules/forever/bin/forever
/usr/local/bin/fhem.js -> /usr/local/lib/node_modules/fhem.js/bin/fhem.js

> fhem.js@2.5.1 postinstall /usr/local/lib/node_modules/fhem.js
> ./bin/postinstall

User for running fhem.js (fhem)? fhem

ok, user is valid

/usr/local/lib
└── fhem.js@2.5.1

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.0.0 (node_modules/fhem.js/node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.0.17: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"arm"})


nach  kommt

fhem.js
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: /usr/local/lib/node_modules/fhem.js/server.js
fs.js:558
  return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
                 ^

Error: EACCES: permission denied, open '/var/log/fhem.js.log'
    at Object.fs.openSync (fs.js:558:18)
    at Object.forever.startDaemon (/usr/local/lib/node_modules/fhem.js/node_modules/forever/lib/forever.js:460:14)
    at /usr/local/lib/node_modules/fhem.js/node_modules/forever/lib/forever/cli.js:319:15
    at /usr/local/lib/node_modules/fhem.js/node_modules/forever/lib/forever/cli.js:162:5
    at /usr/local/lib/node_modules/fhem.js/node_modules/forever/lib/forever.js:409:24
    at FSReqWrap.oncomplete (fs.js:112:15)


alternativ habe ich es mit "sudo" ausgeführt:
sudo fhem.js
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: /usr/local/lib/node_modules/fhem.js/server.js



läuft nun der Server?

hier noch der Inhalt meiner params.js
// set debugging (0,1,2)
exports.debug = 0;

// port on which node.js service is reachable, if fhem.js is running as non-root, port must be greater than 1000
exports.nodePort = 8086;

// Hostname or IP of the FHEM server
exports.fhemHost = 192.168.2.109;

// telnet port of FHEM server
exports.fhemPort = 7072;

// extended mode
// 0 - no JsonList2 pushed on change of device (better performance)
// 1 - JsonList2 of device emitted to clients on changed values
exports.extendedMode = 0;

// poll in seconds for refresh fhem devices
// just for keeping buffer sync to fhem server
// in case of connection problems or configuratuion changes
// that may not sent from fhem by inform on
exports.pollForAllDevices = 600

// webserver root directory:
// path for Webfiles (html,css,js, ...) !! no php !!
// change to path of web directory only if you want to deliver
// web files by this server
// set to false else
exports.pathHTML = false;
//exports.pathHTML = '/var/www/homepage';

// default html page
exports.indexHTML = 'index.html';

// use SSL for connections (true/false)
exports.useSSL = false;

// use connection password (true/false)
// it is recommended to use this only if useSSL is also true
// else the password is send as plain text
exports.useClientPassword = false;

// location of sha-256 hashed password
// only needed if useClientPassword = true
// create it on Linux shell with
// echo -n "mein Passwort" | sha256sum | cut -d' ' -f1 > /etc/fhem.js/pw_client_auth
exports.connectionPasswordFile = '/etc/fhem.js/pw_client_auth';

// location of SSL and client-auth certificats
// only used then useSSL set to true
exports.sslcert =
{
   key:    '/etc/ssl/private/bundle/ssl.key',
   cert:   '/etc/ssl/private/bundle/allcert.pem',
}
exports.cipher = 'HIGH:!aNULL:!MD5';

// use this application for providing mySql values to fhem
// before using this feature first install mysql modul with
// npm install -g mysql

exports.readDB = false;

// fhem.js reads every "refresh" seconds from "table"."column" ordered by "sort" desc one value
// from database "fhem"@"localhost" and set the fhem dummy device "fhem_name" to this value.
//
// in /etc/fhem.js (default) must exist a file named pw_host_user containing password for mysql connection
// every possible combination of host and user from readDBvalues below requires a password file

exports.pwdir = '/etc/fhem.js';

exports.readDBvalues =
[
   {table: 'wetterstation.em1010_readings', column: 'total_energy', sort: 'datetime', fhem_name: 'sunenergy', refresh: 60, host: 'localhost', user: 'fhem' },
   {table: 'wetterstation.em1010_readings', column: 'power', sort: 'datetime', fhem_name: 'sunpower', refresh: 60, host: 'localhost', user: 'fhem' },
   {table: 'wetterstation.weather', column: 'wind_speed', sort: 'datetime', fhem_name: 'windspeed', refresh: 60, host: 'localhost', user: 'fhem' },
   {table: 'wetterstation.weather', column: 'wind_gust', sort: 'datetime', fhem_name: 'windgust', refresh: 60, host: 'localhost', user: 'fhem' },
];

exports.message404 = '<html><head><title>404 Not Found</title></head><body bgcolor="white"><center><h1>404 Not Found</h1></center></body></html>';

// -------------------------------------------------------------
// new for 2.4.11 <-- please don't change or delete this line
// -------------------------------------------------------------

// if fhem.js is running as non-root, nodePort must be greater than 1000

// if fhem.js is running as non-root and useSSL is set to true, make sure that the non-root user has read access
// to the files defined in param sslcert above;
// -------------------------------------------------------------
// new for 2.4.7 <-- please don't change or delete this line
// -------------------------------------------------------------

// do version check for fhem.js after every defined interval
// the result of this check is written to the log and emitted with tag "version" to all connected clients
exports.doCheckVersion = true;
exports.checkVersionInterval = 12;  // in hours

// filter out device values that containing following tag:
exports.filterOutTags = ['deviceMsg:', 'pct:', 'level:', 'timedOn:', 'desired-temp:'];


wenn ich nun auf dem Android im FHEMswitch folgendes eingebe:
URL fhem.js serverim Heimnetzfhem.js Passwort hab ich leer gelassen
URL FHEM Webserverim Heimnetzwird mir in der App gesagt:
Keine Verbindung zum fhem.js Server möglich:
-URL prüfen
-ist der Server online

Habe genau das gleiche Problem.
Habe festgestellt, das gar kein Telnet installiert war. Das habe ich nachgeholt.
Erhalte aber dann eine Passworteingabe. Keins meiner bekannten Passwörter funktioniert. Habe nie eins gesetzt
pi@raspberrypi3:~ $ telnet localhost 7072
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Password:

In der log steht:
26.11.2017 17:18:58 listen for http requests
26.11.2017 17:18:58 aktValues:
26.11.2017 17:18:58 {}
26.11.2017 17:18:58 initFinished
26.11.2017 17:18:58 listen for websocket requests on port 8086 without SSL
26.11.2017 17:18:58 start connection to fhem server
26.11.2017 17:18:58 versionCheck after 43200000
26.11.2017 17:18:58 process error: Error: listen EADDRINUSE :::8086 - retry in 10 secs
26.11.2017 17:18:58 connected to fhem server for listen on changed values
26.11.2017 17:18:58 changed data:
26.11.2017 17:18:58 ��Password: ��

26.11.2017 17:18:58 error: telnet connection closed - try restart in 10 secs


Muss unter FHEM allowed_telnetPort auch der Port 7072 eingetragen werden? Dort steht 21.

Tazz

#154
Habe es jetzt nach über einer Woche hinbekommen.  ::)
Was negativ aufgefallen ist:
  • Der Ordner /run/fhem wird nach einem Neustart nicht erstellt.
  • sudo update-rc.d fhem.js enable sorgt nicht dafür, dass fhem.js beim neustarten gestartet wird
  • In der nodetest.html muss wss: durch http: ersetzt werden:  var socket = io.connect('http://192.168.1.103:8088',
Ich habe den Tipp hier befolgt und somit festgestellt, dass in die postinstall.sh vermutlich das "d" fehlt
Zeile 56: echo "d /run/fhem 0755 $USER root - -" > $PIDDIRCONF
Danach wird auch der Ordner /run/fhem angelegt

Was ich nicht hinbekommen habe ist, dass fhem.js beim Hochfahren gestartet wird?
Welchen Inhalt muss die fhem.js.service Datei haben, damit es beim Neustart gestartet wird?

Werner Schäffer

Entschuldigung dass es solange mit einer Antwort gedauert hat.

Danke Fuzz für deine ausführliche Beschreibung der Probleme die auftraten. Das meiste hast du ja inzwischen selbst gelöst. Ich habe die von dir angesprochenen Punkte in die Doku (Beitrag 1 in diesem Thread) aufgenommen und werde demnächst auch ein neues Release ins npm-Repository laden, indem dann einige von dir angesproche Probleme gelöst sein werden.

Bleibt noch der Autostart von fhem.js:

die Installationsprozedur erzeugt einen Autostart-Mechanismus nach der alten init.d Methode. Diese Methode wird aber eigentlich auch immer noch durch den neuen Systemd-Mechanismus unterstützt. Deshalb meine Frage an Fuzz:

Starte mal Folgendes:

sudo service fhem.js start

Was passiert da. Was steht in den /var/log/fhem.js.* Files?

Tazz

Hallo, mittlerweile habe ich auch gemerkt, dass es mit ws:// geht anstatt zu erst gedacht http://

Bei Ausführung von
sudo service fhem.js start
Wird kein Eintrag in den beiden logs fhem.js.log / fhem.js.error erzeugt.

Gestartet wird es aber scheinbar:

pi@raspberrypi3:~ $ ps aux | grep node
root      3383  1.3  3.2 113596 31168 ?        Ssl  02:21   0:03 /usr/local/bin/node /usr/local/lib/node_modules/fhem.js/server.js


Ich habe mich mit dem Anlegen der fhem.js.service Datei unter /etc/systemd/system beholfen. Inhalt:
[Unit]
Description=fhem.js
Wants=network.target
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/node /usr/local/lib/node_modules/fhem.js/server.js

[Install]
WantedBy=multi-user.target

Bin mir aber nicht sicher, ob die Einträge so richtig sind. Zumindest scheint es beim booten gestartet zu werden.


Gibt es eine Möglichkeit von bestimmten Devices bestimmte Readings zu abonnieren?
Sowas wie
socket.emit('getCertainValueOnChange','fhem-device-name', 'reading-name' ); Das gleiche dann für getOnce
Dann könnte man auf die größeren Datenpakete beim json2 verzichten.

Werner Schäffer

@tazz

um festzustellen ob fhem.js tatsächlich läuft kannst du auch folgenden Befehl ausführen:

lsof -i :8086


wobei 8086 der Port aus /etc/fhem.js/params.js ist. Falls fhem.js  erfolgreich gestartet wurde wird dann eine Zeile in der Art

node    8987 fhem   10u  IPv6 10893438      0t0  TCP *:8086 (LISTEN)

angezeigt.


Werner Schäffer

Zitat von: Tazz am 30 Dezember 2017, 02:53:37
...
Bei Ausführung von
sudo service fhem.js start
Wird kein Eintrag in den beiden logs fhem.js.log / fhem.js.error erzeugt.
...

Existieren die beiden Files und hat der User fhem darauf Schreibrechte? Falls irgendwie nein versuch mal:

touch /var/log/fhem.js.log
touch /var/log/fhem.js.error
chown fhem:fhem /var/log/fhem.js.*



Zitat von: Tazz am 30 Dezember 2017, 02:53:37
...
Gibt es eine Möglichkeit von bestimmten Devices bestimmte Readings zu abonnieren?
Sowas wie
socket.emit('getCertainValueOnChange','fhem-device-name', 'reading-name' ); Das gleiche dann für getOnce
Dann könnte man auf die größeren Datenpakete beim json2 verzichten.
...

Gibt es zur Zeit nicht, könnte aber noch realisiert werden. Mal schauen.

Tazz

#159
Musste die Gruppe fhem vorher anlegen und habe den User fhem dort hinzugefügt:
sudo addgroup fhem
sudo usermod -aG fhem fhem
Danach:
sudo service fhem.js start
Aber es wird nichts in beide Logs geschrieben.
fhem.js läuft aber weiterhin

Per sudo fhem.js wird etwas in die .log geschrieben:
ZitatError: ENOENT: no such file or directory, open '/var/run/fhem/fhem.js.pid'
    at Object.fs.openSync (fs.js:663:18)
    at Object.fs.writeFileSync (fs.js:1314:33)
    at writePid (/usr/local/lib/node_modules/fhem.js/node_modules/forever/bin/monitor:13:6)
    at exports.Monitor.<anonymous> (/usr/local/lib/node_modules/fhem.js/node_modules/forever/bin/monitor:46:5)
    at exports.Monitor.EventEmitter.emit (/usr/local/lib/node_modules/fhem.js/node_modules/eventemitter2/lib/eventemitter2.js:339:22)
    at /usr/local/lib/node_modules/fhem.js/node_modules/forever-monitor/lib/forever-monitor/monitor.js:177:10
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickCallback (internal/process/next_tick.js:180:9)

Für mich sieht es so aus, als würde fhem.js sich nicht an die beiden Angaben halten:
LOGFILE=/var/log/fhem.js.log
ERRORLOG=/var/log/fhem.js.error


Habe sogar exports.debug = 2; aber es wird nichts in die Logs geschrieben.

Bin leider kein Raspbian Experte


Werner Schäffer

ZitatError: ENOENT: no such file or directory, open '/var/run/fhem/fhem.js.pid'

Prüfe bitte:

existiert das Verzeichnis /var/run/fhem ?
falls ja ist der Owner des Verzeichnisses fhem?
ist /var/run ein symbolischer Link auf /run?

Tazz

#161
existiert das Verzeichnis /var/run/fhem ?  nein. Angelegt.
falls ja ist der Owner des Verzeichnisses fhem?  nein. Owner geändert sudo chown fhem:fhem /var/run/fhem
ist /var/run ein symbolischer Link auf /run?  ja

Das Verzeichnis /var/run/fhem verschwindet wieder nach jedem Reboot.
Wenn es angelegt ist und ich fhem.js starte per:
sudo service start fhem.js
wird in dem Verzeichnis nichts angelegt und die Logs bleiben weiterhin leer.

Erst per
sudo fhem.js wird in die Log (fhem.js.log) geschrieben und eine fhem.js.pid in das Verzeichnis erstellt. Bis zum Reboot...

$ sudo find / -name fhem.js
/opt/fhem/www/codemirror/fhem.js
/root/.npm/fhem.js
/root/.npm/registry.npmjs.org/fhem.js
/usr/local/lib/node_modules/fhem.js
/usr/local/lib/node_modules/fhem.js/bin/fhem.js
/usr/local/lib/node_modules/fhem.js/etc/fhem.js
/usr/local/lib/node_modules/fhem.js/etc/init.d/fhem.js
/usr/local/bin/fhem.js
/usr/bin/fhem.js
/etc/fhem.js
/etc/init.d/fhem.js



//Edit:
Ein getDeviceOnce wäre auch extrem hilfreich.
Denn aktuell ist es nicht möglich beim Start meiner App sofort z.B. auf spezielle Readings wie z.B. das Power/Consumption von Steckdosen oder den controlMode von Heizungs-Thermostaten zuzugreifen. Man muss erst auf deren Update warten.
Ich würde es sogar selber programmieren aber ich habe den Aufbau vom fhem.js nicht so ganz verstanden und weiß nicht, wo die Datei mit den ganzen Funktionen zu finden ist.


//Edit2:
Wo ist der Unterschied zw. getValueOnChange und getDeviceOnChange, außer beim Namen? dataMasked ist identisch. Oder übersehe ich da etwas?
socket.on('getValueOnChange', function(data) {
        mylog("request for getValueOnChange " + data, 1);
        //var dataMasked = data.replace(/_/g, 'UNDERLINE');
        var dataMasked = data;
        if (typeof(socket.rooms) == 'undefined' || typeof(socket.rooms[dataMasked]) == 'undefined') {
            socket.join(dataMasked);
        }
    });;
  socket.on('getDeviceOnChange', function(data) {
        mylog("request for getDeviceOnChange " + data, 1);
        //var dataMasked = 'device' + data.replace(/_/g, 'UNDERLINE');
        var dataMasked = data;
        if (typeof(socket.rooms) == 'undefined' || typeof(socket.rooms[dataMasked]) == 'undefined') {
            socket.join(dataMasked);
        }
});

Werner Schäffer

getValueOnChange und getDeviceOnChange sind tatsächlich identisch. Das liegt daran dass die Unterscheidung ein Ansatz ist für Json2List Abfragen. Aber es ist noch nicht über einen Ansatz hinausgekommen.

Tazz

Habe mich jetzt die Tage mit Socket.IO beschäftigt und es verstanden.
Somit konnte ich auch selber getDeviceOnChange korrigieren und getDeviceOnce erstellen.
Bei getDeviceOnChange erzeuge ich nur für dieses Device einen eigenen Room, der abonniert wird.
Bei getDeviceOnce benutze ich eine Kopie der getDevice Function, reduziert um die ganzen ios.sockets.in.... und nur ein ios.sockets.emit('device', deviceJSON); am Ende.
Alles quick&dirty programmiert.
Falls Interesse besteht, kann ich meine server.js hier hochladen.

Werner Schäffer

Zitat von: Tazz am 01 Januar 2018, 15:15:02
...
Wo ist der Unterschied zw. getValueOnChange und getDeviceOnChange, außer beim Namen? dataMasked ist identisch. Oder übersehe ich da etwas?
...

Im neuesten Release 2.5.14 gibt es nun tatsächlich einen Unterschied, der dann auch dafür sorgt dass

getValueOnChange einen veränderten Wert ausliefert und
getDeviceOnChange bei Änderung eines Messwertes ein FHEM-Json2 der Device liefert

Darüberhinaus sind in dieser Version noch einige kleinere Unstimmigkeiten in der Installationsroutine gepacht.