OWFS + MySQL + SwitchKing + Temperatur.nu

OWFS - One Wire File System är en Linuxmjukvara som stödjer de flesta kommersiellt tillgängliga 1wire-enheterna. OWFS saknar helt möjligheter att presentera data - detta måste göras med tex RRDTool
Kategoriregler
Vill du visa bilder i ditt inlägg? Använd funktionen "Ladda upp bilaga" nedanför textrutan!
riro
Tar hemautomation på allvar
Inlägg: 161
Blev medlem: 19 feb 2008, 15:35
Ort: Falun

OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av riro »

Har knåpat ihop lite script som är hyffsat smidiga att använda om man, som jag, kör med OWFS, MySQL, SwitchKing och rapporterar till temperatur.nu.


Först behöver du skapa en databas med lite tabeller.
MySQL-Script

Kod: Markera allt

CREATE DATABASE  1wire;
USE 1wire;

CREATE USER '1wireuser'@'%' IDENTIFIED BY '1wirepassword';
GRANT USAGE ON * . * TO  '1wireuser'@'%';
GRANT ALL PRIVILEGES ON  1wire . * TO '1wireuser'@'%';

CREATE TABLE IF NOT EXISTS 1wiresensors (
  id int(11) NOT NULL AUTO_INCREMENT,
  sensorpath varchar(24) NOT NULL,
  enabled tinyint(1) NOT NULL,
  name varchar(64) NOT NULL,
  LowTempReport tinyint(1) NOT NULL,
  SwitchKingID int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (id)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS 1wirevalues (
  id int(11) NOT NULL AUTO_INCREMENT,
  reporttime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  sensorid int(11) NOT NULL,
  sensorvalue float NOT NULL,
  PRIMARY KEY (id),
  KEY sensorid (sensorid),
  KEY rptTime (reporttime)
) ENGINE=InnoDB;

ALTER TABLE 1wirevalues
  ADD CONSTRAINT 1wirevalues_ibfk_1 FOREIGN KEY (sensorid) REFERENCES 1wiresensors (id) ON DELETE CASCADE ON UPDATE CASCADE;

CREATE VIEW vSensorValues AS
SELECT
  1wiresensors.name AS name,
  1wirevalues.reporttime AS reporttime,
  1wirevalues.sensorvalue AS sensorvalue
FROM (1wiresensors JOIN 1wirevalues ON (1wirevalues.sensorid = 1wiresensors.id) );
Exempel på innehåll kan du lägga till med dessa:

Kod: Markera allt

-- Dummy sensors
INSERT INTO 1wiresensors (sensorpath, enabled, name, LowTempReport, SwitchKingID) VALUES ('10.123456789100', 1, 'Utomhus Öster', 1, 10);
INSERT INTO 1wiresensors (sensorpath, enabled, name, LowTempReport, SwitchKingID) VALUES ('10.123123123123', 1, 'Utomhus Väster', 1, 11);
INSERT INTO 1wiresensors (sensorpath, enabled, name, LowTempReport, SwitchKingID) VALUES ('10.232323232323', 1, 'Köket', 0, 12);
INSERT INTO 1wiresensors (sensorpath, enabled, name, LowTempReport, SwitchKingID) VALUES ('10.929292929292', 1, 'Sovrum', 0, 13);
INSERT INTO 1wiresensors (sensorpath, enabled, name, LowTempReport, SwitchKingID) VALUES ('10.999999999999', 0, 'Test Sensor', 0, 0);
-- Dummy values
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (1, 11);
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (1, 12);
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (1, 13);
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (2, 1);
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (2, 2);
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (2, 3);
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (3, -10);
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (3, -11);
INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (3, -12);
Nu behöver du skapa lite datakällor i SwitchKing, bara att välja att dom ska matas via REST API'et.
Uppdatera sensors-tabellen med rätt SwitchKing ID för datakälla/sensor. Det är alltså en datakälla per sensor.
När du ändå har SwitchKing igång, passa på att skapa en extra källa "Min temp utomhus".
(ID't på den källan ska in i PHP-scriptet)


Sen skapar du ett PHP-script som läser sensor-tabellen och skriver in datat i values-tabellen... och när scriptet ändå har läst av 1-wire nätet så passar den vidare informationen till SwitchKing och Temperatur.nu.

nano /data/read1wire.php

Kod: Markera allt

<?
// OWFS
define("OWFS_MOUNTPOINT", "/mnt/1wire/");

// MySQL Database
define("DB_USER", "1wireuser");
define("DB_PASSWORD", "1wirepassword");
define("DB_DATABASE", "1wire");
define("DB_SERVER", "127.0.0.1");

// SwitchKing REST API
define("SK_ENABLED", true);
define("SK_REST_SERVER", 127.0.0.1");
define("SK_REST_PORT", "8800");
define("SK_REST_USER", "UserName");
define("SK_REST_PASS", "SomePassword");

// LowTemp: Need XX sensors to report low temp
define("LOWTEMP_MINOK", 1);

// LowTemp: temperatur.nu
define("TMPNU_ENABLED", true);
define("TMPNU_STATION", "minstation");
define("TMPNU_ID", "123123123");

// LowTemp: SwitchKing DataSource ID
define("SK_LOWTEMP_ID", "44");

// ---------------------------------------------------------------------------------------------------------

// Other stuff...
define('CRLF', "\r\n");
define('TAB', "\t");


function openDb() {
    global $dbConnection;

    $options = array(
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
        PDO::ATTR_EMULATE_PREPARES   => false,
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION
    );

    try {
        $dbConnection = new PDO('mysql:dbname=' . DB_DATABASE . ';host=' . DB_SERVER, DB_USER, DB_PASSWORD, $options);
    } catch (PDOException $err) {
        echo ('Connection failed: ' . $err->getMessage());
        $dbConnection = null;
    }
}

function updateSwitchKing($id, $temp) {
	if (SK_ENABLED) {
		echo "SwitchKing: Adding value " . $temp . " for id " . $id . CRLF;

		$context = stream_context_create(array(
			'http' => array(
				'header'  => "Authorization: Basic " . base64_encode(SK_REST_USER . ":" . SK_REST_PASS)
			)
		));

		$url = "http://" . SK_REST_SERVER . ":" . SK_REST_PORT . "/Datasources/" . $id . "/addvalue?value=" . $temp;
		$data = file_get_contents($url, false, $context);

		$xml = simplexml_load_string($data);
		if ($xml->Successfull == "true") {
			echo "SwitchKing: Successfull" . CRLF;
			return true;
		} else {
			echo "SwitchKing: Error! " . $xml->Info . CRLF;
			return false;
		}
	} else {
		echo "SwitchKing: Disabled - Not reporting " . $temp . " for sensor " . $id . CRLF;
	}
}

function updateSqlTemp($sensorId, $temp) {

    echo "SQL: Adding temp " . $temp . " for sensor " . $sensorId . CRLF;
    try {
		// Add to MySQL
	    global $dbConnection;
	    $stmt = $dbConnection->prepare("INSERT INTO 1wirevalues (sensorid, sensorvalue) VALUES (:sensorId, :sensorValue)");
	    $stmt->bindValue(":sensorId",    $sensorId, PDO::PARAM_STR);
	    $stmt->bindValue(":sensorValue", $temp,     PDO::PARAM_STR);
	    $stmt->execute();
    } catch (PDOException $err) {
        echo "SQL: Failed: " . $err->getMessage() . CRLF;
        return false;
    }

    echo "SQL: OK!" . CRLF;
    return true;
}

function updateTemperaturNu($temp) {
	if (TMPNU_ENABLED) {
		echo "Temperatur.nu: Reporting temp " . $temp . CRLF;

		// Post to Temperatur.nu
		$url = "http://www.temperatur.nu/report/puttemp.php?s=" . TMPNU_STATION . "&id=" . TMPNU_ID . "&t=" . $temp;
		$data = file_get_contents($url);

		if (strpos($data, "ok!") === false) {
			echo "Temperatur.nu: Not OK " . $data . CRLF;
		} else {
			echo "Temperatur.nu: OK " . CRLF;
		}
	} else {
		echo "Temperatur.nu: Disabled - Not reporting " . $temp . CRLF;
	}
}

function closeDb() {
    global $dbConnection;
    $dbConnection = null;
}

function readSensor($sensorpath) {
	$fileName = OWFS_MOUNTPOINT . $sensorpath . "/temperature";

	if (file_exists($fileName)) {
		$data = trim(file_get_contents($fileName));
		return $data;
	} else {
		return $fileName . " - Not Found";
	}
}

// --------------------------------------------------------------------------------------------------------------
openDb();
global $dbConnection;

$lowTemp = 999;
$lowTempSensorOk = 0;
$lowTempFail = 0;

syslog(LOG_INFO, "1-Wire Reader: Starting to read 1-Wire sensors ...");
foreach($dbConnection->query("SELECT * FROM 1wiresensors WHERE enabled = true") as $sensor) {
	echo "Main: Reading sensor " . $sensor["sensorpath"] . " - " . $sensor["name"] . CRLF;

	$temp = readSensor($sensor["sensorpath"]);

	if (is_numeric($temp)) {		
		echo "Main: Temperature: " . $temp . CRLF;


		// Store low temp
		if ($sensor["LowTempReport"] == true) {
			if ($temp <= $lowTemp) {
				$lowTemp = $temp;
				$lowTempSensorOk ++;			
				echo "LowTemp: Found new low temp " . $lowTemp . "  Total OK sensors: " . $lowTempSensorOk . CRLF;
			}
		}

		// Post to SwitchKing
		updateSwitchKing($sensor["SwitchKingID"], $temp);

		// Add to MySQL
		updateSqlTemp($sensor["id"], $temp);

	} else {
		echo "Main: Failed to read: " . $temp . CRLF;
		syslog(LOG_ERR, "1-Wire Reader: Failed to read: " . $temp);
		if ($sensor["LowTempReport"] == true) {
			$lowTempFail ++;
			echo "Main: LowTempReport enabled sensor, total failcount: " . $lowTempFail . CRLF;
		}
	}

	echo CRLF;
}


if ($lowTempSensorOk >= LOWTEMP_MINOK) {
	echo "Main: LowTemp Reporting (OK sensors: " . $lowTempSensorOk . ", temp: " . $lowTemp . ")" . CRLF;
	syslog(LOG_DEBUG, "1-Wire Reader: Reporting low temp: " . $lowTemp);

	// Post to SwitchKing (LowTemp)
	updateSwitchKing(SK_LOWTEMP_ID, $lowTemp);

	// Post to Temperatur.nu
	updateTemperaturNu($lowTemp);
} else {
	echo "Main: LowTemp Disabled, only " . $lowTempSensorOk . " sensors OK, failed to read: " . $lowTempFail . CRLF;
	syslog(LOG_ERR, "1-Wire Reader: Failcount on low temp is " . $lowTempFail . " ... reporing aborted.");
}

closeDb();

syslog(LOG_INFO, "1-Wire Reader: Done reading 1-Wire sensors ...");
echo CRLF;
exit;

?>
Ja, självklart behöver du redigera lite... lite förklaring på det som kanske inte är helt självklart:
LOWTEMP_MINOK - Minsta antalet sensorer med LowTempReport satt till 1 som ska vara tillgängliga för att rapportering av lägsta temp skall göras.
SK_LOWTEMP_ID - IDt i SwitchKing som lägsta temp skall tryckas in.

Sen ett litet shell-script för att köra PHP-snurran (vill inte köra flera instanser av den parallelt):
nano /data/read1wire.sh

Kod: Markera allt

#!/bin/sh
SCRIPTNAME=`basename $0`
PIDFILE=/var/run/${SCRIPTNAME}.pid


# Kolla om PID-filen finns
if [ -f ${PIDFILE} ]; then
		# Lever processen?
        OLDPID=`cat ${PIDFILE}`
        RESULT=`ps -ef | grep ${OLDPID} | grep ${SCRIPTNAME}`

        if [ -n "${RESULT}" ]; then
                echo "Script already running! Exiting"
                exit 255
        fi
fi

# Skapa PID-fil
echo $$ > ${PIDFILE}

# Kör PHP och läs av 1-wire nätet
/usr/bin/php /data/read1wire.php

# Ta bort PID-filen
if [ -f ${PIDFILE} ]; then
        rm ${PIDFILE}
fi
Se till att shellscriptet blir körbart:

Kod: Markera allt

chmod +x /data/read1wire.sh

Och sedan ska det så klart köras via crontab'en, var 3e minut kanske blir lagomt?
crontab -e

Kod: Markera allt

*/3 * * * * /data/read1wire.sh

... hoppas jag inte missade en massa småsaker nu ... :)
Användarvisningsbild
bertilson
Tar hemautomation på allvar
Inlägg: 133
Blev medlem: 21 dec 2009, 11:41
Ort: Borås

Re: Sv: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av bertilson »

Intressant, jag har tänkt att ha från rrdtool till MySQL.

Men varför kör du ett php script? Vad är fördelen från att göra allt i ett shell script?

Trodde att php bara var till för websidor

Skickat från min LT26i via Tapatalk 2
riro
Tar hemautomation på allvar
Inlägg: 161
Blev medlem: 19 feb 2008, 15:35
Ort: Falun

Re: Sv: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av riro »

bertilson skrev: Men varför kör du ett php script? Vad är fördelen från att göra allt i ett shell script?
Helt enkelt för att jag känner mig bekväm med PHP. :)

Sen är PHP bara ett scriptspråk i mängden som fungerar bra att köra på webbservrar... och det fungerar lika bra att köra direkt i shell.
Användarvisningsbild
CirruZZ
Master Moderator
Inlägg: 1621
Blev medlem: 13 feb 2008, 16:46
Ort: Ystad

Re: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av CirruZZ »

Jag använder också PHP till annat än bara web sidor, funkar toppen. Det är som riro skriver, bara vad man kännes sig bekväm med.
Användarvisningsbild
elf98
Hemautomation - det är mer än en hobby
Inlägg: 5434
Blev medlem: 27 okt 2006, 13:49
Ort: Linköping
Kontakt:

Re: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av elf98 »

Backend och spindeln till temperatur.nu är skriven helt i php.
Grundade m.nu & temperatur.nu

Driver temperatur.nu

Bild
JeoG
Wannabe
Inlägg: 12
Blev medlem: 18 dec 2012, 16:20
Ort: Norrköping

Re: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av JeoG »

Tack för en mkt bra guide!
Äntligen får jag in mina 1wire givare i en databas och i switchking.
Men går det på något sätt kommentera bort överföringen till Temperatur.nu.
Litar inte riktigt på mina prylar ännu, så vill gärna labba lite mer innan jag börjar bidra till Temperatur.nu
riro
Tar hemautomation på allvar
Inlägg: 161
Blev medlem: 19 feb 2008, 15:35
Ort: Falun

Re: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av riro »

Det är ren PHP så ändra raden 186 från

Kod: Markera allt

   // Post to Temperatur.nu
   updateTemperaturNu($lowTemp);
till:

Kod: Markera allt

   // Post to Temperatur.nu
   // updateTemperaturNu($lowTemp);
Alltså // i början för att kommentera ut.
JeoG
Wannabe
Inlägg: 12
Blev medlem: 18 dec 2012, 16:20
Ort: Norrköping

Re: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av JeoG »

riro skrev:Det är ren PHP så ändra raden 186 från

Kod: Markera allt

   // Post to Temperatur.nu
   updateTemperaturNu($lowTemp);
till:

Kod: Markera allt

   // Post to Temperatur.nu
   // updateTemperaturNu($lowTemp);
Alltså // i början för att kommentera ut.
Tack! Är inte så hemma på PHP, blir mest klippa och klistra bland skript man hittar. Sen hoppas man på det bästa!
JeoG
Wannabe
Inlägg: 12
Blev medlem: 18 dec 2012, 16:20
Ort: Norrköping

Re: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av JeoG »

En liten fråga, vet inte om det är rätt att ta det i den här tråden.

Då jag är total nybörjare på PHP :oops:

Om jag lagrar värden med hjälp av scripten ovan.
Finns det då något enkelt sätt att printa ut ifrån mySQL databasen Nuvarande/Max/Min värde för dom olika sensorerna på en PHP sida? Är bara ute efter att få det i ren text.
shuu
Wannabe
Inlägg: 7
Blev medlem: 27 dec 2013, 23:00
Ort: sjöbo

Re: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av shuu »

Utan att ge någon kod till dig så kan jag säga att det är lätt fixat, det går att göra med ca 20 rader kod.
shuu
Wannabe
Inlägg: 7
Blev medlem: 27 dec 2013, 23:00
Ort: sjöbo

Re: OWFS + MySQL + SwitchKing + Temperatur.nu

Inlägg av shuu »

JeoG skrev:Tack för en mkt bra guide!
Äntligen får jag in mina 1wire givare i en databas och i switchking.
Men går det på något sätt kommentera bort överföringen till Temperatur.nu.
Litar inte riktigt på mina prylar ännu, så vill gärna labba lite mer innan jag börjar bidra till Temperatur.nu
Såg att detta redan var besvarat men snyggare att göra såhär.. Nu är detta för SwitchKing men samma gäller för konstanten för TMPNU_ENABLED, onödigt att ändra i koden när det finns inställningar för det :)

Kod: Markera allt

define("SK_ENABLED", true);
till

Kod: Markera allt

define("SK_ENABLED", false);
Skriv svar