Modul zur Nutzung der Raspberry Pi GPIO

@Wladimir: Offenbar ist es so, dass man die notwendigen manuellen Schritte für die Einrichtung der 1-Wire-Schnittstelle aktuell über raspi-config erledigen kann. Das wäre gut!

Hier mal der relevante Ausschnitt zum Anschluss von einer FHEM-Seite:

Dazu wird im ersten Schritt der 1-Wire Bus (bzw. zum Test nur ein einzelner Sensor) mit dem GPIO-Port des RPi verbunden, und zwar

1-Wire GND an GND vom Pi (Pin 6)
1-Wire Datenleitung an GPIO04 (Pin 7)
1-Wire VDD an +3,3V vom Pi (Pin 1)
Ausserdem ist noch ein Pullup-Widerstand von z.B. 4,7kOhm zwischen Pin1 und Pin7 zu schalten.

Obwohl die nominale Spannung für 1-Wire Devices 5V beträgt, ist hier die verringerte Spannung nötig, weil die GPIO-Ports des RPi nur 3,3, V vertragen und durch höhere Spannungen zerstört werden. Als Alternative kann man den 1-Wire Bus auch 5V (Pin 2) anschließen, dann muss aber zwingend das Signal der 1-Wire Datenleitung durch einen Spannungsteiler (z.B. 10 kOhm und 6.8 kOhm) auf 3,3 V begrenzt werden. Besser man verwendet einen aktiven Pegelwandler der sich mit einem einfachen MOS-FET realisieren lässt

Auf dem Weg würden dann aber wohl nur die DS18B20 funktionieren, das aber ohne einen weiteren Adapter.

Joachim

Hallo Joachim,

habe zum Test einen DS18B20 direkt am PI angeschlossen.
Als vorlage die seite https://www.einplatinencomputer.com/raspberry-pi-1-wire-temperatursensor-ds1820-ansteuern/
Per PuTTY verbunden.
Paar Befehle ausgführt: sudo modprobe wire
sudo modprobe w1-gpio
sudo modprobe w1-therm

Ohne welche Skripte zu installieren, bei ausführen: cat /sys/bus/w1/devices/10-000802f973a0/w1_slave
Antwort
24 00 4b 46 ff ff 0d 10 68 : crc=68 YES
24 00 4b 46 ff ff 0d 10 68 t=17937

Mein IPS läuft auf Windows, habe noch keine funktionierende Lösung gefunden die Daten zu holen:banghead:

Zum Modul. Für mich würde es reichen nur die DS18B20 einlesen, andere sensoren sind nicht in planung.
Ich kenne nicht den Aufwand so ein Modul zu schreiben, ob es lohnt nur für die Sensoren?

@all kennt jemand eine funktionierende Losung?
Daten vom 1-Wire (DS1820) am entferntem PI vom IPS auf Windows holen?

Danke

Hi Wladi,

schau dir mal meine PDF an, ich habe das schon mal auf einem IPS Stammtisch vorgeführt. Läuft bei mir jetzt seit 2 Jahren ohne Probleme.

Gruss
Bernd

Rasp_JSON_1Wire.pdf (354 KB)

Hallo Wladimir,

eine neue Instanz zu erstellen ist nicht so schwer. Jedoch ist hier die Herangehensweise eine gänzliche andere. Da ich das für eine gute Ergänzung halte werde ich mich damit mal inhaltlich beschäftigen. Kann aber bis zur vollständigen Funktion ein paar Tage dauern. Aber ich denke in Dir habe ich ja zumindest einen versierten Tester gefunden!:wink:

Insbesondere bei der Abbildung der n-Sensoren im Objektbaum habe ich noch - im Gedankenmodell - ein paar offene Fragen, ansonsten wird wohl die vom Modul schon vorhandene SSH-Verbindung und einige Dateioperationen genutzt…

Joachim

Hallo Joachim,

Mea Culpa, ich hatte Ursache und Wirkung verwechselt. Der Timer WAR deaktiviert, zeigte nur halt im Objektbaum immer noch den letzten Wert (10 Sek,) an. Davon lies ich mich verwirren… Sorry! Das Toggeln des Portpins löste mein Script aus, das die Werte aktualisiert hat… (Kam also wirklich nicht vom Timer bzw. Ereignis!)

Ok, ich habe dann alle Instanzen des PCF8574 aus dem IPS gelöscht. Aber der zyklische (10 Sek.) Toggle auf dem Input Pin GPIO4 , der trat weiterhin auf. Dann habe ich mir gesagt, nimm doch mal einen anderen Portpin, einen der möglichst weit weg ist von GPIO4 (Immerhin liegt I2C ja auf GPIO2 und 3). Entschieden habe ich mich für den Pin GPIO24 und siehe da es funktioniert. Seitdem herrschte Ruhe. Dann habe ich die PCF8574 Instanzen wieder angelegt, diesmal alle gleich mit Wiederholungszyklus 0 und es funktioniert seither. Nur wenn ich ein Signal an einem der Eingänge der Portexpander anlege wird ein Interrupt erzeugt, der dann wiederum die Notifikation des Portpins auslöst, mein Script aufruft und den Eingangsport ausliest! Perfekt! Fall erledigt!

Vielen, lieben Dank für deine geduldige Unterstützung! Ich bin sicher, das dein Modul erst vielen ermöglichen wird die Möglichkeiten des Raspis ins IPS zu integrieren…

Gruß…

Ralf

@Bernd Danke für die Anleitung.

habe folgenden Code getestet:

<?
$Sensor = "10-000802f973a0";
$temperatur = implode('', file("/sys/bus/w1/devices/".$Sensor."/w1_slave"));
$temperatur = substr($temperatur, strpos($temperatur, "t=") +2);
$temperatur = round(($temperatur/1000),1);

$alte_temperatur = GetValueFloat(39496 /*[Raeume\Badezimmer\1Wire\1]*/);

if ($temperatur <> $alte_temperatur)
   {
   SetValueFloat(39496 /*[Raeume\Badezimmer\1Wire\1]*/, $temperatur);
   $rpc = new JSONRPC ("http://pi:123456@192.168.178.52/api/");
   $rpc->SetValue(39496 /*[Raeume\Badezimmer\1Wire\1]*/, $temperatur);
   } 
?>

wirft Fehler:
Warning: file(/sys/bus/w1/devices/10-000802f973a0/w1_slave): failed to open stream: No such file or directory in C:\IP-Symcon\scripts\13330.ips.php on line 3
Warning: implode(): Invalid arguments passed in C:\IP-Symcon\scripts\13330.ips.php on line 3

Was ist falsch an dem Code oder verstehe ich grundsätzlich was falsch?
Muss auf dem Raspi auch ein IPS-Server laufen? und da dieser Code laufen?
Magst du mich ein bischen erläuchten. Sorry Das Problem sitzt schon wieder mal vor dem PC.:smiley:

@Joachim, Testen mach ich gerne;)

Eine Bitte: das Thema bitte in einem eigenen Thread diskutieren…[emoji6]

Zur Information:

  • 1-Wire: da Bernd und Wladimir diesen Wunsch geäußert haben und auch ich diese Möglichkeit interessant findet bin ich dabei das zu implementieren…

  • Pi-Face digital 2: klingt passend. Ich bitte aber um Verständnis, das es mir zu teuer ist dieses nur zu bestellen um es für Euch zu implementieren. Wenn die Interessenten sich zusammen tun und mir das Teil dauerhaft zu Verfügung stellen (zur Implementierung und später um ggf. Korrekturen einzufügen, Änderungen vorzunehmen bzw. Fehler nachzuvollziehen) könnte da ein Schuh draus werden…

  • I²C-Multiplexer: Spontane Idee mit der Annahme es wird nur ein Multiplexer überhaupt an Bus 1 angeschlossen, dann könnte man das ggf. in den Splitter implementieren. (Ich habe aber immer noch Befürchtungen bzw. der Steuerung der Datenströme…)

Joachim

die I2C Adresse kann nicht durch den Benutzer geändert werden. Bitte setzen Sie einen I2C-Multiplexer ein. Ich verwende dieses (sehr günstige) Breakout Board:

Adafruit TCA9548A I2C Multiplexer - Schnittstellen - Module

Die Ansteuerung ist denkbar einfach, es gibt auch ein Tutorial bei Adafruit:

Overview | Adafruit TCA9548A 1-to-8 I2C Multiplexer Breakout | Adafruit Learning System

Mit freundlichen Grüßen aus Reutlingen

Martin Herold

Kannst du auch die Adressen von 0x70-0x77 zum einstellen hinzufüge dann sollte es doch einfach so mit dem multiplexer funktionieren?

Gesendet von meinem SM-G935F mit Tapatalk

Hallo Martin,

ganz so einfach ist es leider nicht. Der Multiplexer (habe hier auch welche rumliegen) stellt ein eigenes Device dar. Er muss angesteuert werden wie jedes andere Gerät auch.
Vom Prinzip läuft das dann so:

  • Umschaltung auf Kanal 1 des Multiplexers
  • Abfrage oder Senden der Daten von/an den n-Devices auf Kanal 1
  • Umschaltung auf Kanal 2 des Multiplexers
  • Abfrage… usw.

Es ist überhaupt kein Ding, dieses Device als neues Gerät zu implementieren, jedoch ergeben sich unheimlich viele Möglichkeiten daraus, weil jedes Device dahinter eine Art „Vorwahl“ hat. Im Moment sind noch ein paar andere Dinge auf der To-Do-Liste die Vorrang haben. Es fehlt mir ehrlich gesagt im Moment auch die zündende Idee, wie ich das abbilden soll - kommt aber vielleicht noch…:wink:

Joachim

Wenn ich da so mitdenke, würde ich den Multiplexer NICHT als Device implementieren.Das bekommt man nicht sortiert.

Ich würde es so machen: Bei den vorhandenen Devices wie BME280 oder iaq folgendes in der Config ergänzen:

o Gerät befindet sich am Multiplexer (zum Ankreuzen)
__ Multiplexer Adresse __ Multiplexer Kanal

Macht man den Haken an, muss das Device vorab nur die beiden Steuerkommandos an den Multiplexer absenden. Das Ganze dann in einer Semaphore kapseln, damit das auch sequenziell passiert und nicht zufällig ein Device den Multiplexer bedient, während ein anderes noch daraus liest.

…Device im Sinne der Struktur muss es schon deshalb werden, weil es ein Handle benötigt damit es über PIGPIO angesprochen werden kann.

Im Moment verfolge ich - bisher rein gedanklich - folgende Idee. In den I²C-Instanzen gibt es ja die Busauswahl. Wenn Multiplexer als Device angelegt worden sind, erscheinen diese in der Busauswahl (Bus 0, Bus 1, Multiplexer x an Kanal y…)

Wird jetzt das Device angesprochen erfolgt die „Vorwahl“ über die Angabe in diesem Pull-Down-Menü.
Mit den Semaphore wäre eine Möglichkeit, muss aber mal sehen, ob das dann in der Struktur eines PHP-Moduls so funktioniert wie ich mir das vorstelle…

Ansonsten sind aber noch ein paar andere Baustellen die ich gerne vorab abgearbeitet haben möchte:

  • letzte Ergänzungen an der Heizungs-Einzelraumsteuerung (IPS2SingleRoomControl)
  • ein paar Details an meinem Enigma-Modul (IPS2Enigma)
  • das gewünschte 1-Wire-Modul
  • das gewünschte Modul für das Piface

Joachim

Warum den Multiplexer nicht als Splitter einbauen?
Der macht das Umschalten und den sync. Und die anderen Instanzen braucht man dann nicht ändern.
Michael

Multiplexer unterstützung wäre echt sehr schön :-). Darf gern priorisiert werden

Gesendet von meinem SM-G935F mit Tapatalk

…was den Multiplexer angeht hatte ich vorhin so einen schönen Text als Antwort auf Michaels Hinweis geschrieben - offensichtlich aber vergessen es abzusenden…:rolleyes:

Im Kern: Um das hierarchisch einigermaßen korrekt abzubilden wäre meine Idee einen Multiplexer in die bestehende Splitter-Instanz zu integrieren. Das würde nach meiner Vorstellung bedeuten, dass man dann insgesamt sechs I²C-Busse hätte (Bus1 + vier für den Multiplexer + Bus 0).
Die Auswahl des gewählten Busses erfolgte dann über die jeweiligen Instanz-Formulare - ich meine, dass sollte doch eigentlich genug Möglichkeiten eröffnen?

Zum anderen: Bitte mal auf einen Testaufbau für 1-Wire schauen. Nach einem Update kann diese - wenn der 1-Wire-Server am Raspberry Pi (raspi-config) aktiviert und die 1-Wire 18x20 korrekt angeschlossen sind mit

I2G_GetOneWireData(ID der IO-Instanz);

aufgerufen werden.
Ergebnisse sind dann nur bei den Meldungen sichtbar!
Was auffällt: Der Zugriff auf die Datei, die den Messwert enthält dauert finde ich sehr lange…:confused:
Dieses ist übrigens schon auf dem Raspberry Pi selbst auffällig gewesen, wenn man nur versucht, mal mit MC da reinzuschauen.

Neu übrigens:

  • Einige Erweiterungen in der HTML-Darstellung im Enigma2-Modul
  • Neues Modul zur Heizungs-Einzelraumsteuerung

Joachim

Hallo Joachim,

nachdem ich mich zwischenzeitlich ein bisschen mit dem ESP8266 beschäftigt hatte, bin ich nun wieder zu deinem Modul zurückgekehrt und habe auch sogleich wieder einen Verbesserungsvorschlag. Da ich aber sehe, dass Du dich gerade an anderer Stelle engagierst würde ich diesen natürlich hinten anstellen… mit low Priority…

Zu dem Vorschlag…
Ich habe mal die PCF8574 ohne I2C Verbindung in Betrieb genommen und festgestellt, dass die Pins nach dem einschalten der Stromversorgung ein High Signal ausgeben. Genauso ist es wenn ich den Raspi ohne LAN Verbindung, aber mit, über I2C, angeschlossenen PCF8574 starte und pigpiod von Deinem Modul, wegen dem fehlendem Netzwerk, keine Befehle bekommen kann.
Das Problem ist nun, dass Du nach einem Reconnect als Initialisierung jeden Ausgangs Port auf Low setzt. (Die Eingänge hast Du ja auf meinen Wunsch hin bereits auf High gesetzt) Das bedeutet, dass er nach dem einschalten der Versorgungsspannung, wie gesagt, auf High geht und Dein Modul ihn nach einem Reconnect mit IPS auf Low schaltet. Das führt in jedem Fall zu einem schalten der Ausgänge! Egal ob die an dem Ausgang hängende Schaltung als Low oder High Aktiv konzipiert ist. Wobei, wahrscheinlich ist sie Low Aktiv, weil der Baustein nämlich geradezu dafür prädestiniert ist, denn er kann nur 500 Mikroampere als High Signal ausgeben, aber 12 Milliampere als Low Signal aufnehmen. Selbst für eine LED sind die 500 Mikroampere zu wenig. Also wird man ihn fast immer als Low Aktiv betreiben.

Worauf will ich hinaus…!? Ich würde vorschlagen das du je Baustein (Instanz) oder besser noch je Pin des Bausteins die Wahl zwischen Low und High Aktiv bietest. So wie auf deiner Konfig Seite mit Ein- und Ausgang und Logging ja/nein.
Im Augenblick kommt nämlich noch dazu, das wenn man den Baustein als Low Aktiv betreibt, dann ist immer die Visualisierung der Portzustände genau falsch herum! Das wäre demnach auch ein Punkt der bei dieser Änderung zu berücksichtigen wäre.
Die zu ändernde Punkte wären also…

  1. Erweiterung der Konfigurationsseite des PCF8574 Moduls
  2. Es müsste bei jeder Initialisierung bei der Auswahl Low Aktiv ein High Signal für den Port Pin gesetzt werden (Egal ob Eingang oder Ausgang) und umgekehrt ein Low Signal bei High Aktiv. Eingänge müssten dann von den Usern generell auf Low Aktiv gesetzt werden. Die Änderung die Du für mich eingebaut hast, würde dann dadurch ersetzt.
  3. Die Anzeige des aktuellen Zustands in allen Variablen müsste sich entsprechend der Konfiguration von Low oder High Aktiv entsprechend verhalten. Also bei Low Aktiv „AN“ zeigen wenn der 8574 eine 0 an dem Pin zurückmeldet und umgekehrt eine „Aus“ anzeigen wenn eine 1 an dem Pin ansteht.

Sollte das Ganze allerdings mit zuviel Aufwand verbunden sein, wäre es vielleicht zumindest im ersten Schritt besser, als Initialisierungswert eine Eins in ALLE Portpins zu schreiben, nicht nur in die Eingänge. Dann würde es zumindest beim starten nicht zu einem unbeabsichtigten Schalten externer Hardware kommen… Das die Statusvisualisierung dann nicht der Realität entspricht, kann man vielleicht anderweitig umgehen oder damit leben.

Danke für die viele Zeit die Du in dies alles investierst…

Gruß

Ralf

Hallo Ralf,

hänge im Moment noch beim 1-Wire, werde das aber versuchen schnellst möglich nachzuführen!

Hier noch mal zum Thema 1-Wire:
Das ist der Code im Prinzip

  1. SFTP Verbindung zum Raspberry Pi
  2. Schauen ob die Verzeichnis-Struktur des 1-Wire-Servers existiert
  3. die angeschlossenen DS1820 ermitteln
  4. die 1w_slave-Datei auslesen, um den Messwert zu ermitteln

Ist im Prinzip auch ganz einfach, nur der Zugriff auf die Datei mit dem Messwert dauert „ewig“!
Schritte 1 bis inkl. 3 liegen bei ungefähr 3 Sekunden, bis die Ergebnisse da sind weitere 30-45 Sekunden!

Ich habe keine Ahnung warum es so lange dauert, diese Datei auszulesen. Die Messung des DS wird im Internet mit ungefähr 750ms angegeben…
Wenn man sich direkt auf den Raspberry Pi einloggt und versucht z.B. mit mc die Datei zu lesen, dauert es auch ungewöhnlich lange…

Hat jemand eine Erklärung dafür?

Joachim

Hallo Joachim,
bei mir braucht mein Ausleseskript ~12000ms bis alle 7 Ds18S20 Werte da sind.
Nutze ich für meine Heizungssteuerung, die komplet per Skripten gemacht ist.
Hier noch mal mein skript, wie es bis heute klaglos läuft :


<?
$id = IPS_GetParent($_IPS['SELF']);
$id2= IPS_GetParent($id);
$id3= IPS_GetObjectIDByName("GPIO Temperatur", $id2);
//------------------------------------------------------------------------------
 if($_IPS['SENDER'] == "Execute")                // nur wenn bei "Ausführen"
 {
   CreateVariableByName($id3, "onewireId", 3);
   CreateVariableByName($id3, "onewirezaehler", 1);
   $onewireID = IPS_GetObjectIDByName("onewireId", $id3);
   SetValue($onewireID, "");
   $vid = CreateVariableByName($_IPS['SELF'], "Running", 0);
   $eid = CreateEventIDByName($_IPS['SELF'], "StartStop", 0);
   IPS_SetEventActive($eid, true);
   IPS_SetEventTrigger($eid, 0, $vid);
   IPS_SetEventScript($eid, $_IPS['SELF']);
   $zaehler = intval(exec('cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count'));
   $onewirezaehlerID = IPS_GetObjectIDByName("onewirezaehler", $id3);
   SetValue($onewirezaehlerID, $zaehler);

	$datei = file("/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves");
	$i=1;
	foreach($datei AS $dallas_id)
   {
	   $ds_id[$i]= $dallas_id;
      $wire = GetValue($onewireID);
      $wire = "".$wire." ".$ds_id[$i];
  	   SetValue($onewireID, $wire);
		$i++;
   }
 }
//------------------------------------------------------------------------------
// if($_IPS['SENDER'] == "TimerEvent")             //
$onewireID = IPS_GetObjectIDByName("onewireId", $id3);
$onewirezaehlerID = IPS_GetObjectIDByName("onewirezaehler", $id3);
$zaehler = GetValue($onewirezaehlerID);
//$zaehler = intval(exec('cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count'));

$wire = GetValue($onewireID);
$ds_id = explode(" ", $wire);
	for ($i = 1; ; $i++)
	{
	   if ($i > $zaehler) {
	        break;
      }
      $ds_id[$i]= trim($ds_id[$i]);
		$temp = exec('cat /sys/bus/w1/devices/'.$ds_id[$i].'/w1_slave |grep t=');
		$crc = exec('cat /sys/bus/w1/devices/'.$ds_id[$i].'/w1_slave | grep crc | sed "s/^.*\(...\)$/\1/"');
		$temp = explode('t=',$temp);
      //The power-on reset value of the temperature register is +85°C
		if($crc =="YES" and $temp[1] !== "-62" and $temp[1]  !== "85000") //Fehler raus, -1.2 °C ,85°C und CRC
		{ 
			$temp = $temp[1] / 1000;
			$temp = round($temp,2);
	  	   $id = CreateVariableByName($id3, $ds_id[$i], 2);
		   SetValue($id, $temp);
	   }
	}
//------------------------------------------------------------------------------
 if($_IPS['SENDER'] == "Variable")
 {
  if($_IPS['VALUE'])
  {
   IPS_SetScriptTimer($_IPS['SELF'], 10);         // Sekunden-Takt
  } else {
   IPS_SetScriptTimer($_IPS['SELF'], 0);
  }
 }
//------------------------------------------------------------------------------
//##############################################################################
function CreateVariableByName($id, $name, $type)
{
   $vid = @IPS_GetVariableIDByName($name, $id);
   if($vid===false) {
      $vid = IPS_CreateVariable($type);
      IPS_SetParent($vid, $id);
      IPS_SetName($vid, $name);
   }
   return $vid;
}
//##############################################################################
function CreateEventIDByName($id, $name, $type)
{
   $eid = @IPS_GetEventIDByName($name, $id);
   if($eid===false) {
      $eid = IPS_CreateEvent($type);
      IPS_SetParent($eid, $id);
      IPS_SetName($eid, $name);
   }
   return $eid;
}
?>

Hallo Joachim,

die lange laufzeit kann ich bestätigen mit

I2G_GetOneWireData(ID der IO-Instanz);  

Das Skript

<?
$Sensor = "10-000802f973a0";
$temperatur = implode('', file("/sys/bus/w1/devices/".$Sensor."/w1_slave"));
$temperatur = substr($temperatur, strpos($temperatur, "t=") +2);
$temperatur = round(($temperatur/1000),1);

$alte_temperatur = GetValueFloat(15294 /*[1-Wire\1]*/);

if ($temperatur <> $alte_temperatur)
   {
   SetValueFloat(15294 /*[1-Wire\1]*/, $temperatur);
   $rpc = new JSONRPC ("http://xxx.xxxx@xxx.de:12345678@192.168.1.38:3777/api/");
   $rpc->SetValue(39496, $temperatur);
   }
   
?>

braucht ~840 ms. Über PuTTY kommt die Antwort auch recht flott. Es ist zurzeit nur ein DS1820 angeschlossen.

Zu Schritt 1-3. Muss das jedes mal ermittelt werden? Würde es nicht reichen im Instanzkonfigurator einstellen?

Ich stell mir das so vor: Im Instanzkonfigurator Schaltfläche „Suchen“ führt Schritte 1bis 3 aus und listet die ermittelte Sensoren auf.
Ein Pull-Down-Menü bittet die auswahl an.

Wladimir