Metadata-Version: 2.4
Name: jeedomdaemon
Version: 2.0.0
Summary: A base to implement Jeedom daemon in python
Author: Mips
Project-URL: Homepage, https://github.com/Mips2648/jeedom-daemon-py
Keywords: JEEDOM,DAEMON,ASYNCIO
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Build Tools
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: aiohttp>=3.14.3
Dynamic: license-file

# jeedom-daemon-py

[![pytest 3.11](https://github.com/Mips2648/jeedom-daemon-py/actions/workflows/pytest-3.11.yml/badge.svg)](https://github.com/Mips2648/jeedom-daemon-py/actions/workflows/pytest-3.11.yml)
[![Sponsor Mips2648](https://img.shields.io/badge/Sponsor-Mips2648-ea4aaa?logo=githubsponsors)](https://github.com/sponsors/Mips2648)

[![pytest 3.13](https://github.com/Mips2648/jeedom-daemon-py/actions/workflows/pytest-3.13.yml/badge.svg)](https://github.com/Mips2648/jeedom-daemon-py/actions/workflows/pytest-3.13.yml)

## Description

This library provides everything needed to build a daemon for a plugin for Jeedom in python.
It's possible to get a daemon skeleton by typing literally less than 5 lines of code.

## Requirements

* **Python 3.11+**

## How to install

Make sure to add it in your requirements

### Manually

```bash
pip3 install jeedomdaemon
```

### Via Jeedom core packages.json

```json
{
  "pre-install": {},
  "apt": {},
  "pip3": {
    "jeedomdaemon": {}
  },
  "npm": {},
  "yarn": {},
  "plugin": {},
  "post-install": {}
}
```

### Via requirements.txt

```txt
jeedomdaemon~=2.0.0
```

## Quick start

Create a file `myDaemon.py` and copy/past the 4 lines of code below and that's it, nothing else to do, your daemon is good to start:

```python
from jeedomdaemon import BaseDaemon

class MyDaemon(BaseDaemon):
    pass

MyDaemon().run()
```

Of course, this does nothing so far except starting, accepting incoming requests from your php code and stopping when it is needed.

So let's add few lines in your daemon class:

```python
from jeedomdaemon import BaseDaemon

class MyDaemon(BaseDaemon):
    def __init__(self) -> None:
        # Standard initialisation
        super().__init__(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 starts.
        This is the place where you should create your tasks, login to remote system, etc
        """
        # if you don't have specific action to do on start, do not create this method
        pass


    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.
        """
        pass

    async def on_stop(self):
        """
        This callback will be called when the daemon needs to stop`
        You need to close your remote connexions and cancel background tasks if any here.
        """
        # if you don't have specific action to do on stop, do not create this method
        pass

MyDaemon().run()
```

## Configuration

Without additional work, your daemon will accept following argument when started by your php code:

* --loglevel - a string (Jeedom format) giving the log Level for the daemon
* --sockethost - usually not needed, default is '127.0.0.1'
* --socketport - port on which the daemon will open a tcp socket to listen for incoming message from your php code
* --callback - callback url to use by your daemon to send data to your php code
* --apikey - the API key use to valid communication
* --pid - the pid filename
* --cycle - a float value giving at which frequency the daemon should send requests to your PHP code, by default every 0.5s (max)
* --maxchangespercycle - maximum number of changes (final keys) sent in a single request, by default 5000
* --maxpayloadsize - maximum approximate size in bytes of a single request payload, by default 524288 (512 KB)

Changes added with `add_change` are queued and sent in batches: a batch stops as soon as one of the two limits above is reached, and the next batch is sent shortly after (without waiting a full cycle) as long as the queue is not empty. This avoids sending a huge payload to Jeedom when a burst of changes occurs, e.g. at start-up. A single value bigger than `--maxpayloadsize` is sent alone so it never blocks the queue.

It will happen that you need to receive some additional values from Jeedom to be able to start your daemon, like a user & password to login somewhere. In that case create a child class like in this example and provide it during daemon initialisation:

```python
from jeedomdaemon import BaseDaemon
from jeedomdaemon import BaseConfig

class DemoConfig(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("--user", type=str, default='Harrison')
        self.add_argument("--password", type=str)

class MyDaemon(BaseDaemon):
    def __init__(self) -> None:
        # provide your custom config class during init
        super().__init__(config=DemoConfig(), on_start_cb=...)

        # ...

```

## What's next

I suggest you to take a look at this [demo plugin](https://github.com/Mips2648/jeedom-aiodemo) which implements this library
