OWFS + MySQL + SwitchKing + Temperatur.nu
Postat: 01 feb 2013, 09:39
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
Exempel på innehåll kan du lägga till med dessa:
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
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
Se till att shellscriptet blir körbart:
Och sedan ska det så klart köras via crontab'en, var 3e minut kanske blir lagomt?
crontab -e
... hoppas jag inte missade en massa småsaker 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) );
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);
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;
?>
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
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 ...
