Jag har min Tellstick ansluten till en dator som sitter bak på TVn.
Servern står i källaren.
Dessa script är på TV-datorn:
callbacks.py:
Kod: Markera allt
from ctypes import c_int, c_ubyte, c_void_p, POINTER, string_at #imports allowing the use of our library
from threading import Timer
import time
import platform
#import urllib2
import os
#import MySQLdb
#platform specific imports:
if (platform.system() == 'Windows'):
#Windows
from ctypes import windll, WINFUNCTYPE
lib = windll.LoadLibrary('TelldusCore.dll') #import our library
else:
#Linux
from ctypes import cdll, CFUNCTYPE
lib = cdll.LoadLibrary('libtelldus-core.so.2') #import our library
timers = {} #timerlist
def turn():
if (devid == "12" or devid == "13" or devid == "14"):
run = "/usr/bin/php /var/www/autosys/python_to_php.php " + statusen + " " + devid
print "...RUNNING " + run
os.system(run)
print "...DONE running " + run
#function to be called when a device event occurs
def callbackfunction(deviceId, method, value, callbackId, context):
global timers
t = 0
print "Received event for device %d" % (deviceId,)
global devid
global statusen
devid = str(deviceId)
statusen = str(method)
os.system('/usr/bin/php /var/www/autosys/tdtool_status.php')
if (deviceId in timers):
# a timer already exists for this device, it might be running so interrupt it
# Many devices (for example motion detectors) resends their messages many times to ensure that they
# are received correctly. In this example, we don't want to run the turnOn/turnOff methods every time, instead we
# start a timer, and run the method when the timer is finished. For every incoming event on this device, the timer
# is restarted.
t = timers[deviceId]
t.cancel()
t = Timer(0.5, turn) #start timer
t.start()
timers[deviceId] = t #put timer in list, to allow later cancellation
#function to be called when device event occurs, even for unregistered devices
def rawcallbackfunction(data, controllerId, callbackId, context):
raw1 = string_at(data)
run_raw = "/usr/bin/php /var/www/autosys/python_to_raw.php \"" + raw1 + "\""
print "...RUNNING " + run_raw
os.system(run_raw)
print "...DONE running" + run_raw
if (platform.system() == 'Windows'):
CMPFUNC = WINFUNCTYPE(c_void_p, c_int, c_int, POINTER(c_ubyte), c_int, c_void_p) #first is return type
CMPFUNCRAW = WINFUNCTYPE(c_void_p, POINTER(c_ubyte), c_int, c_int, c_void_p)
else:
CMPFUNC = CFUNCTYPE(c_void_p, c_int, c_int, POINTER(c_ubyte), c_int, c_void_p)
CMPFUNCRAW = CFUNCTYPE(c_void_p, POINTER(c_ubyte), c_int, c_int, c_void_p)
cmp_func = CMPFUNC(callbackfunction)
cmp_funcraw = CMPFUNCRAW(rawcallbackfunction)
lib.tdInit()
lib.tdRegisterDeviceEvent(cmp_func, 0)
lib.tdRegisterRawDeviceEvent(cmp_funcraw, 0) #uncomment this, and comment out tdRegisterDeviceEvent, to see data for not registered devices
print "Waiting for events..."
while(1):
time.sleep(0.5) #don't exit
Detta är python_to_php.php på samma dator:
Kod: Markera allt
<?php
include 'opendb.php';
include 'func.php';
$dbname = 'auto';
$command = $argv[1];
$device = $argv[2];
mysql_select_db($dbname);
$query = "select * from t_devices where f_tdtool_id=$device";
$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_array($result);
if ($command == "2") {
$job = $row['f_job_off'];
} else {
$job = $row['f_job_on'];
}
$url = "http://adress_till_servern_i_källaren/run_job.php?job=$job";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$status = curl_exec($ch);
curl_close($ch);
include 'closedb.php';
?>
Detta är tdtool_status.php, den uppdaterar databasen med enheternas namn och läge (on eller off)
Kod: Markera allt
<?
include 'opendb.php';
mysql_select_db("auto") or die(mysql_error());
exec("tdtool --list",$datan);
unset($datan[0]); // Vi tar bort första raden. Annars består rad 1 av "Number of devices: 14".
$count = count($datan)+1; //Vi räknar hur många rader det blev
function explodeTabs($singleLine) {
$tabsArr = explode("\t", $singleLine); //vi delar upp statusen från tdtool i delar och skiljer dem åt genom att kolla efter tab.
return $tabsArr;
}
for($i=1;$i<$count;$i++) { //vi kör en loop som börjar på 1 (eftersom att vi har tagit bort 0) och slutar när den har kommit till i antal rader.
$datetime = date('Y-m-d H:i:s');
$lineDetails = explodeTabs($datan[$i]);
$query = "UPDATE t_devices set f_value='" .$lineDetails[2]. "', f_name='" .utf8_decode($lineDetails[1]). "', f_last_sensed='" . $datetime . "' where f_tdtool_id=" . $lineDetails[0];
$result = mysql_query($query)
or die(mysql_error());
//echo "ID : " . $lineDetails[0];
//echo "<br>Namn : " . $lineDetails[1];
//echo "<br>Status: " . $lineDetails[2];
//echo "<br />DB-fråga: $query <br /><br />";
}
?>
Jag kan inte Python så det scriptet har modifierats så gott jag kan. PHP kan jag nog helt OK iallafall. Jag kör ingen validering av datan som scripten matas med eftersom att de bara körs internt. Ingen utifrån har ju tillgång till scripten så några sql-injections eller liknande kommer inte att ske.
Alltså, Pythonscriptet körs på tv-datorn och lyssnar på Duo'n. När man trycker på en knapp på en Nexafjärr så reagerar pythonscriptet. Om det är device 12, 13 eller 14 så skall python_to_php.php köras och till scriptet så skickas deviceid och event (på eller av) med till scriptet. Scriptet kollar i sin tur i databasen vilket jobb som skall köras och anropar sedan ett script via HTTP som kör jobbet. Anledningen till att den anropar via HTTP är för att scripten körs på två olika servrar. Jag kan också göra anropet via SSH men eftersom att jag vill kunna anropa jobb-körar-scriptet via HTTP från olika ställen så blev det bäst så. Varje gång Duon tar emot något så körs också tdtool_status.php som uppdaterar databasen med status och namn på alla mottagare. Detta gör att jag alltid har aktuell status på mina mottagare (ON eller OFF) i databasen. Fördelen med det är att jag kan kolla status i databasen istället för att köra tdtool varje gång. Lite mindre resurser som går åt mao.
Rörigt men förhoppningsvis har någon användning av detta.