Lib # jeedomdaemon 0.9.8
Bonjour @Mips ,
J’essaie d’intégrer la lib en référence dans mon plugin SomfyUnified.
Dans un premier temps, la mise en oeuvre est aisée et la procédure très bien décrite.
Merci pour ce beau travail.
Mais j’avoue que depuis quelques jours, je rame un peu car il y a quelque chose que je n’ai pas compris et je dois passer à coté de quelque chose ?
En quelques mots mais je pourrais développer si cela s’avère nécessaire:
- Lorsque je démarre le Démon du panneau du plugin, le Daemon ‹ start › comme attendu
- Au démarrage Daemon, je retourne le message 'Start à ma fonction de callback
- Puis je lance une boucle avec une période 1 seconde qui elle-même envoi un message ‹ tick › à la fonction callback
Ca ! C’est ce que je pensais obtenir.
Le hic dans tout ca, c’est que si je mets un délai dans la fonction de callback (qui pourrait simuler une durée de traitement, etc, …), ce délai est pris en compte par le Daemon avant sa prochaine action.
Et je prévois un traitement assez long dans mon appli !!!
Est-ce le fonctionnement attendu ?
Ais-je une coquille ou un oubli dans mon code ?
Je ne demande pas un debbugage de mon code en règle car je ne veux pas te prendre trop de temps. Juste un avis.
En espérant avoir été suffisament clair.
Et surtout, avec tous mes remerciements d’avance.
Je joint ci-après copie du code de mes 2 scripts et un screenshot:
- Le Daemon
# SomfyUnified
# @author Eridani78
#
# @version 0.0.0 2024 06 07
#
# Description: Jeedom plugin Daemon user file
# File: somfyunifiedd.py
# ------------------------------------------------------------------------------
import asyncio
from jeedomdaemon.base_daemon import BaseDaemon
from jeedomdaemon.base_config import BaseConfig
# ------------------------------------------------------------------------------
class SUDaemonConfig(BaseConfig):
"""This is where you declare your custom argument/configuration
Remember that all usual arguments are managed by the BaseConfig class already so you only have to take care of yours; e.g. user & password in this case
"""
def __init__(self):
super().__init__()
self.add_argument("--textmessage", type=str, default='')
self.add_argument("--daemontickperiod", type=float, default=1.0)
# ------------------------------------------------------------------------------
class SUDaemon(BaseDaemon):
def __init__(self) -> None:
# Standard initialisation
super().__init__(config=SUDaemonConfig(), on_start_cb=self.on_start, on_message_cb=self.on_message, on_stop_cb=self.on_stop)
# Add here any initialisation your daemon would need
async def on_start(self):
"""
This method will be called when your daemon start.
This is the place where you should create yours tasks, login to remote system, etc
"""
# if you don't have specific action to do on start, do not create this method
self._logger.info("|Dm| ==> '%s'", self._config.textmessage)
# Create a background task: fetch_events_loop
self._logger.info("|Dm| Start fetch_events")
self._fetch_events_task = asyncio.create_task(self._fetch_events_loop(self._config.daemontickperiod))
async def on_message(self, message: list):
"""
This function will be called once a message is received from Jeedom; check on api key is done already, just care about your logic
You must implement the different actions that your daemon can handle.
"""
self._logger.info("|Dm| ==> message['action'] '%s'", message['action'])
async def on_stop(self):
"""
This callback will be called when daemon need to stop`
You need to close your remote connexions and cancel background tasks if any here.
"""
self._fetch_events_task.cancel()
await self.send_to_jeedom({'fetch_events':f'stop'})
self._logger.info("|Dm| Stop fetch_events")
async def _fetch_events_loop(self, tickperiod: float):
"""
This is an implementation of a backgroudn task.
You must have a try ... except asyncio.CancelledError: It will intercept the cancel request from the loop.
"""
self._logger.info("|Dm| Start fetch_events_loop")
await self.send_to_jeedom({'fetch_events':f'start'})
try:
while True:
self._logger.info("|Dm| Loop with period %s sec",tickperiod )
await self.send_to_jeedom({'fetch_events':f'tick'})
await asyncio.sleep(tickperiod)
except asyncio.CancelledError:
self._logger.info("|Dm| Stop fetch_events_loop")
# ------------------------------------------------------------------------------
# START
# ------------------------------------------------------------------------------
SUDaemon().run()
# ------------------------------------------------------------------------------
# END
# ------------------------------------------------------------------------------
- La fonction de callback en test
<?php
/* This file is part of Jeedom.
*
* Jeedom is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jeedom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SomfyUnified
*
* @author Eridani78
* @version 1.0.0 2024 06 15
*
* Description: Callback function to receive communication data from Daemon to PHP code.
*
* File: jeeSomfyUnified.php
*/
/* * ************************** use Declarations ************************ */
use SomfyUnified\UtilsLib;
/* * **************************** Include Files ************************* */
require_once __DIR__ . "/../../../../core/php/core.inc.php";
/* * ******************************************************************** */
try {
// Import pluginId
$pluginId = SomfyUnified::getPluginId();
// Authenticate communication thru Jeedom API key verification
if (!jeedom::apiAccess(init('apikey'), $pluginId)) {
echo __('Access not granted ! ', __FILE__);
exit();
}
if (init('test') != '') {
echo 'OK';
log::add($pluginId, 'info', 'test from daemon');
die();
}
/** Read raw data from the request body ($dataString is a JSON formatted string) */
$dataString = file_get_contents("php://input");
/** Process $dataString */
if (is_null($dataString)) {
log::add($pluginId, 'debug', __FILE__ . ' Data from Daemon is null. Failed to import Data.');
throw new Exception(__FILE__ . ' Data from Daemon is null. Failed to import Data.');
} elseif ($dataString === "") {
$data = $dataString;
} else {
// Decode the JSON formatted string in an appropriate PHP type. JSON object is converted to array)
$data = UtilsLib::decodeIfJson($dataString, null, 512, JSON_INVALID_UTF8_IGNORE | JSON_OBJECT_AS_ARRAY);
if ($data === false) {
log::add($pluginId, 'error', '|Je| $dataString (is NOT JSON)= ' . json_encode($dataString));
//throw new Exception(__FILE__ . ' Data from Daemon imported but (Data is NOT JSON).');
} else {
//log::add($pluginId, 'debug', 'Succeeded to import Data from Daemon (Data is JSON).');
}
}
log::add($pluginId, 'info', '|Je| Message from Daemon received in PHP (json_encode): ' . json_encode($data));
/** Process action from Daemon */
switch (true) {
case ($data === ""):
// Do nothing ("" is automatically send by SUDaemon and received when Daemon start)
break;
case ($data['fetch_events'] === 'start'):
sleep(20);
break;
case ($data['fetch_events'] === 'tick'):
sleep(10);
break;
case ($data['fetch_events'] === 'stop'):
break;
}
} catch (Exception $exception) {
log::add($pluginId, 'error', '|Je| ' . displayException($exception));
}
- Un screenshot montrant que le tick n’est pas espacé d’une seconde mais de 10