LinkTap es un dispositivo para controlar el riego, diseñado y comercializado por una empresa australiana.
Se compone de una válvula y una puerta de enlace al servidor de LinkTap. Con una sola puerta de enlace se pueden instalar varias válvulas. Yo solo tengo una, concretamente el modelo G2.
Llevo usándola un año y medio. En este post comento primero mis impresiones (pros y contras) sobre este dispositivo, y después explico cómo integrarlo en Jeedom.
Contras
- No se puede controlar localmente. La dependencia del servidor de LinkTap es total.
Pros
- Tiene API pública y documentada, lo que significa que hay vías de integración en distintos sistemas de terceros (como puede ser el controlador domótico Jeedom, por ejemplo).
- La válvula que se pone en el grifo funciona a batería, concretamente 4 pilas AA. Para mí es una ventaja porque no tengo tomas eléctricas en la terraza.
- Las pilas duran un año y medio (las acabo de cambiar).
- La comunicación entre la puerta de enlace y la válvula es vía Zigbee pero con una capa propietaria de Linktap. Sin embargo, tiene un gran alcance de cobertura.
- La puerta de enlace se conecta al router por Ethernet. No es wifi.
- Tiene muchos avisos de alertas: Válvula caída, escape de agua, falta de batería, etc..
- Si se va la electricidad, la programación del riego sigue funcionando y además tiene un sistema de protección que no deja la válvula abierta.
En este enlace podéis ver el dispositivo concreto del que os hablo, en la web de LinkTap.
Integración con Jeedom
Yo no soy programadora. El código utilizado en esta integración no lo he hecho yo pero sí que lo he modificado para integrarlo en Jeedom.
El código original lo he sacado de esta url.
Ahí tenéis el código casi completo. Veréis que hay varias funciones:
ACTIVATE_INSTANT_MODE
ACTIVATE_INTERVAL_MODE
QUERY_WATERING_STATUS
GET_ALL_DEVICES
Según la API, aún se pueden definir más funciones y teniendo estos ejemplos, es fácil hacerlo.
En mi caso, solo he utilizado dos funciones porque a las demás no las he visto de interés. Concretamente he utilizado Instant_Mode y Get_All_Devices.
Por lo anterior, he utilizado dos scripts php, uno para encender y apagar el riego y otro para recoger los datos de la válvula.
ENCENDIDO/APAGADO:
Haciendo uso del plugin “Script” de Jeedom, damos de alta a un nuevo dispositivo y agregamos dos comandos “Guión” de tipo acción “por defecto” : uno para el encendido y otro para el apagado. Tal como se ve en la siguiente imagen:
El script php a introducir se llama ONlinkTap.php. Solo tenéis que copiar el contenido del siguiente archivo cuando deis de alta un nuevo script en el plugin, y no os olvidéis de poner la extensión .php al nombre: ONlinkTap.php.
<?php /** Código PHP obtenido de este sitio web: https://community.symcon.de/t/link-tap-bewaesserungssteuerung/52784/10 (muchas gracias!!). * Ver también la web de la API de LinkTapp: https://www.link-tap.com/#!/api-for-developers * Modificado y adaptado para Jeedom por Alicia Hernández. */ $gatewayID = 'xxxxxxxxxxxxxxxx'; // introducir los primeros 16 dígitos sin guiones ni espacios $taplinker1 = 'xxxxxxxxxxxxxxxx'; // introducir los primeros 16 dígitos sin guiones ni espacios $link_tap = new LinkTap('pepe', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', $gatewayID, $taplinker1); //Introducir el nombre de usuario y la clave API //que se obtiene de aquí: https://www.link-tap.com/#!/api-for-developers $on = $link_tap->Watering_On(3); //el número 3 es la duración del riego en minutos. Introducir la duración según conveniencia. Siempre un número entero. $off = $link_tap->Watering_Off(); $argumentoo = $argv[1]; //Argumento que se envía desde la linea de comandos. //En jeedom la construcción del objeto es: /var/www/html/plugins/script/data/ONlinkTap.php on ->Para encender (se deja un espacio entre php y on) //Y /var/www/html/plugins/script/data/ONlinkTap.php off -> Para apagar (dejar el espacio entre php y off). //El nombre de mi archivo php es ONlinkTap.php. echo $$argumentoo.PHP_EOL; //Esta sentencia imprime el resultado de la llamada a la API. Si lo queréis ver, solo hay que añadir otro objeto en el scritp de tipo información (otro). class LinkTap { private const LINK_TAP_BASE_URL = 'https://www.link-tap.com/api/'; private const ACTIVATE_INSTANT_MODE = 'activateInstantMode'; public $username; public $apiKey; public $gatewayId; public $taplinkerId; function __construct(string $username, string $api_key, string $gatewayId, string $taplinkerId) { $this->username = $username; $this->apiKey = $api_key; $this->gatewayId = $gatewayId; $this->taplinkerId = $taplinkerId; } /** Función que enciende el riego: Watering On * @return string: Imprime la respuesta tipo string. */ public function Watering_On(int $duration) { $url = self::LINK_TAP_BASE_URL . self::ACTIVATE_INSTANT_MODE; $data = json_encode([ 'username' => $this->username, 'apiKey' => $this->apiKey, 'gatewayId' => $this->gatewayId, 'taplinkerId' => $this->taplinkerId, 'action' => true, 'duration' => $duration, //'eco' => false, //'ecoOn' => 1, //'ecoOff' => 2 ]); $response = $this->PostData($url, $data); return $response; } /** Función que apaga el riego: Watering Off * @return string */ public function Watering_Off() { $url = self::LINK_TAP_BASE_URL . self::ACTIVATE_INSTANT_MODE; $data = json_encode([ 'username' => $this->username, 'apiKey' => $this->apiKey, 'gatewayId' => $this->gatewayId, 'taplinkerId' => $this->taplinkerId, 'action' => false, 'duration' => 0 ]); $response = $this->PostData($url, $data); return $response; } protected function PostData($url, $data) { $ch = curl_init(); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_URL, $url); $result = curl_exec($ch); if (curl_errno($ch)) { trigger_error('Error:' . curl_error($ch)); } $info = curl_getinfo($ch); $header_out = curl_getinfo($ch, CURLINFO_HEADER_OUT); curl_close($ch); return $result; } } ?>
En ese script, para comando ON, he configurado que riegue 3 minutos. Dentro del script tenéis explicaciones de la forma de cambiar esos 3 minutos por los que estiméis necesarios.
OBTENCIÓN DE LOS DATOS DE LA VÁLVULA:
Con la función “GET_ALL_DEVICES” se obtiene un resultado codificado en Json. Estos son los datos que proporciona:
stdClass Object ( [result] => ok [devices] => Array ( [0] => stdClass Object ( [name] => Riego [location] => Alicante (Alacant), Alicante, España [gatewayId] => XXXXXXXXXXXXX [status] => Connected [version] => B0404262105292252I_C0300051708152305 [taplinker] => Array ( [0] => stdClass Object ( [taplinkerName] => TapLinker [taplinkerId] => XXXXXXXXXXX [status] => Connected [location] => Not specified [version] => T0300022004072253 [batteryStatus] => 29% [workMode] => M [plan] => stdClass Object ( [duration] => 0 [Y] => 2021 [X] => 9 [Z] => 27 [H] => 20 [M] => 1 [ecoOffS] => 0 [ecoOnS] => 0 [ecoOff] => 2 [ecoOn] => 2 [eco] => [action] => ) [watering] => [vel] => 3743 [fall] => [valveBroken] => [noWater] => [leakFlag] => [clogFlag] => [signal] => 64 ) ) ) ) )
De todos esos datos, con el script php llamado LinkTap.php (LinkTap.php) se recogen la mayoría. Este script se añade igual que el anterior, copiamos y pegamos el código sin olvidar poner después del nombre del archivo .php.
<?php /** Código PHP obtenido de este sitio web: https://community.symcon.de/t/link-tap-bewaesserungssteuerung/52784/10 (muchas gracias!!). * Ver también la web de la API de LinkTapp: https://www.link-tap.com/#!/api-for-developers * Modificado y adaptado para Jeedom por Alicia Hernández. */ $gatewayID = 'xxxxxxxxxxxxxxxx'; // introducir los primeros 16 dígitos sin guiones ni espacios $taplinker1 = 'xxxxxxxxxxxxxxxx'; // introducir los primeros 16 dígitos sin guiones ni espacios $link_tap = new LinkTap('pepe', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', $gatewayID, $taplinker1); //Introducir el nombre de usuario y la clave API //que se obtiene de aquí: https://www.link-tap.com/#!/api-for-developers $result = $link_tap->Get_All_Devices(); $status = json_decode($result); //El resultado lo imprime en formato Json. //LOS OBJETOS EN JEEDOM SON DEL TIPO INFORMACIÓN Y DEPENDE DEL DATO SERÁ DEL SUBTIPO DIGITAL (bateria por ejemplo y el caudal) U OTROS (estados de conexión, por ejemplo). //LOS OBJETOS EN EL SCRIPT SE CONSTRUYEN CON EL NOMBRE LA RUTA DE UBICACIÓN DEL ARCHIVO PHP SEGUIDO DE UN ESPACIO Y EL ARGUMENTO (NOMBRE DE LA VARIABLE TAL CUAL). //En este caso el nombre del archivo php es: LinkTap.php y los datos los recojo en las variables siguientes: $conexserv = $status ->devices[0] -> status; //Variable que recoge el estado de conexión al servidor de LinkTap. //Objeto en Jeedom: /var/www/html/plugins/script/data/LinkTap.php conexserv (ojo con el espacio). $conexlink = $status ->devices[0]-> taplinker[0] -> status; //Variable que recoge el estado de conexión de LinkTap a la válvula. //Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php conexlink $bateria = $status ->devices[0]-> taplinker[0] -> batteryStatus; //Recoge el estado de la batería-> /var/www/html/plugins/script/data/LinkTap.php bateria $modo =$status ->devices[0]-> taplinker[0] -> workMode; //Recoge el modo de trabajo. Puede ser M:manual; I:modo a intervalos, etc...(ver:https://www.link-tap.com/#!/api-for-developers). //Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php modo $duration = $status ->devices[0]-> taplinker[0] -> plan ->duration; //Recoge la duración del riego en minutos. ->/var/www/html/plugins/script/data/LinkTap.php duration $Y = $status ->devices[0]-> taplinker[0] -> plan ->Y; //Recoge el año del último riego.->Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php Y $X = $status ->devices[0]-> taplinker[0] -> plan ->X; //Recoge el mes del último riego.->Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php X $Z = $status ->devices[0]-> taplinker[0] -> plan ->Z; //Recoge el día del último riego.->Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php Z $H = $status ->devices[0]-> taplinker[0] -> plan ->H; //Recoge la hora del último riego.->Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php H $min = $status ->devices[0]-> taplinker[0] -> plan ->M; //Recoge los minutos del último riego.->Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php H $vel = $status ->devices[0]-> taplinker[0] -> vel; //Recoge el caudal del último riego.->Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php vel $signal = $status ->devices[0]-> taplinker[0] -> signal; //Recoge la señal de la puerta de enlace a la válvula. ->Objeto en jeedom: /var/www/html/plugins/script/data/LinkTap.php signal $watering = $status ->devices[0]-> taplinker[0] -> watering; //No sé qué recoge porque siempre da nulo pero para algo servirá. $fall = $status ->devices[0]-> taplinker[0] -> fall; //Recoge un fallo de la válvula, si no imprime ningún valor es que la válvula está bien. $valveBroken = $status ->devices[0]-> taplinker[0] -> valveBroken; //Recoge otro fallo de la válvula. $argumento = $argv[1]; echo $$argumento; class LinkTap { const LINK_TAP_BASE_URL = 'https://www.link-tap.com/api/'; const GET_ALL_DEVICES = 'getAllDevices'; public $username; public $apiKey; public $gatewayId; public $taplinkerId; function __construct(string $username, string $api_key, string $gatewayId, string $taplinkerId) { $this->username = $username; $this->apiKey = $api_key; $this->gatewayId = $gatewayId; $this->taplinkerId = $taplinkerId; } /** Función que recoge los datos de las válvulas: Get All Devices * @param (string $gatewayId) * @return string */ public function Get_All_Devices() { $url = self::LINK_TAP_BASE_URL . self::GET_ALL_DEVICES; $data = json_encode([ 'username' => $this->username, 'apiKey' => $this->apiKey, 'gatewayId' => $this->gatewayId, ]); $response = $this->PostData($url, $data); return $response; } protected function PostData($url, $data) { $ch = curl_init(); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_URL, $url); $result = curl_exec($ch); if (curl_errno($ch)) { trigger_error('Error:' . curl_error($ch)); } $info = curl_getinfo($ch); $header_out = curl_getinfo($ch, CURLINFO_HEADER_OUT); curl_close($ch); return $result; } } ?>
En Jeedom creamos un nuevo dispositivo haciendo uso del plugins “Script” y añadimos tantos comandos como datos vamos a recoger. Esos comandos son del tipo “Guión”, “información” y subtipos “digital” u “otros”. El subtipo va a depender del tipo de dato que sea.
Adjunto una captura de pantalla:
Ambos scripts, ONlinkTap.php y LinkTap.php, contienen instrucciones.
Así es cómo quedan en el tablero principal de Jeedom:
Y así es cómo queda el virtual (plugin “Virtual” de Jeedom) realizado para algunos datos:
Por último, añadir que las llamadas a la API de LinkTap están limitadas. En el caso de encendido/apagado del riego, el límite de llamadas es cada 15 segundos.
En el caso de la recogida de los datos (Get_All_Devices), el límite de llamada es cada 5 minutos.
Por este motivo, he dividido el código en dos y creado dos scripts en Jeedom y además he creado un escenario que actualiza los datos cuando riega.
En el escenario, el disparador es programado (Lunes, Miércoles y Sábado a las 20:00h) y las reglas son las siguientes:
En las reglas del escenario, el tiempo de 180 segundos que he definido es insuficiente porque, como ya dije al principio, la API solo permite llamadas a los datos de linktap cada 5 minutos.
Creo que eso es todo. ¡Espero que os sirva!
¡Impresionante Alicia!
Ya estabas tardando en pasar a Jeedom. Pero veo que la espera ha merecido la pena. ¿Sigues usando y teniendo tu eedomus o lo has pasado todo a Jeedom?
Increíble como manejas ya Jeedom en poco tiempo…
Si, Philippe sigo con eedomus.
Estoy para comprarme el jeedom atlas ya que hora lo tengo en una raspberry.
Poco a poco iré migrando.
Gracias Philippe.
¡Maravillosa publicación Alicia!
Me encanta tú solución para integrar un temporizador de agua inalámbrico como link tap en Jeedom.
Tú publicación está muy bien explicada y con todo lujo de detalles, creo que será de gran ayuda a quien tengan proyectos iguales o similares.
Muchas gracias y te animo que sigas publicando.
Gracias.
Hola Alicia,
Te felicito por esa integracion.
Tengo este sistema de riego y me encantaria poder integrarlo a mi eedomus.
Intente seguir los pasos, pero en eedomus es algo diferente de Jeedom y el script no se puede añadir asi, se tiene que adaptar y no tengo el conocimiento suficiente de eedomus scripting como para hacer esos cambios yo mismo.
Me gustaria saber si tambien integraste este sistema Linktap a tu eedomus y en tal caso, si podrias compartir como lo hiciste ?
Gracias de antemano por tu respuesta
Slds
/Jean
Hola Jean: En eedomus el script no va a funcionar porque eedomus utliza un lenguaje php simplificado.
No sé hasta que punto este script se podría adaptar para que funciones en eedomus. No lo he probado y creo que tampoco sabría hacerlo.
Lo que sí puedes hacer es colocar el script en un servidor externo (un NAS, por ejemplo. Incluso a lo mejor te sirve dropbox) y desde eedomus hacer las llamadas al script para recuperar los datos y demás funcionalidades.
Otra cosa que podrías hacer es instalar Jeedom en una raspberry. Integrar el riego en Jeedom siguiendo este manual y después pasarte los datos a eedomus desde jeedom a traves de las APIs de ambos sistemas.
Siento no poder serte de más ayuda.
Salu2