PiApplications 2026
Mise à jour du 29/10/2026.

JmpSolar : guide utilisateur.

Ce guide a pour objectif de vous accompagner dans l'utilisation du système de régulation JmpSolar. Il s'agit d'un logiciel utilisé comme régulateur de puissance délivrée par une batterie Marstek en collaboration avec un wattmètre Shelly Pro EM. Il s'appuie sur les API ouvertes de ces deux constructeurs afin de s'assurer d'une certaine pérennité.

Cibles.

Il s'agit d'un programme console développé sur la base de l'infrastructure Qt 6.12 ou version ultérieure. Le système d'exploitation cible est Linux ou une appliance compatible tel qu'un NAS. Il est disponible en version binaire pour les architectures x86_64 et ARM64. Il a été testé avec succès sur une machine physique sous Debian 13 et une machine virtuelle Debian 13 exécutée par une Freebox.

Les versions proposées sont au format AppImage. Ce sont des application auto-suffisantes. Le format AppImage est un format de conteneur qui contient l'application ainsi que toutes ses dépendances. L'installation de Qt 6.12 ou version ultérieure est donc inutile.

Pour utiliser jmpsolar, on préférera une machine qui reste allumée en permanence. Il est recommandé de placer le programme dans un environnement qui permet sa relance en cas de panne secteur prolongée. A cet effet, nous donnerons un exemple d'utilisation en tant que service systemd.

Configuration et lancement.

La forme générale de la ligne de commande pour un lancement manuel est :

jmpsolar.AppImage [options] <IP:port UDP (Venus)> <http://IP (Shelly)> [nom du fichier de configuration]

Arguments.

L'ordre des arguments est important. Le tableau qui suit les présente :

Indice   Point de connexion UDP Exemple Rôle
1 Obligatoire <Adresse ou alias IP>:<N° de port UDP> 192.168.0.10:30000 Fourni au régulateur les paramètres de connexion au port UDP de la Venus. Notez le double point entre les deux paramètres : il est obligatoire. 30000 est le numéro de port par défaut de la Venus.
2 Obligatoire <http|https>//<adresse ou alias IP du wattmètre Shelly> http://192.168.0.11 Fourni au régulateur le préfixe d'URL qui lui permet de communiquer avec le serveur web embarqué par le wattmètre.
3 Facultatif [nom du fichier JSON de configuration] /etc/jmpsolar.json

Le fichier de configuration permet de définir une ou plusieurs des options possibles. Cela évite de les saisir sur la ligne de commande mais pas seulement.
Lorsqu'un fichier de configuration est fourni à la ligne de commande, il est possible de modifier à chaud les options. Pour cela les étapes à suivre sont :

  1. Modifier le fichier de configuration dont le nom a été saisi sur la ligne de commande.
  2. Identifier le numéro de processus (PID) du régulateur. Par exemple la commande suivant le permet :
    ps -e | egrep jmsolar
  3. Emettre le signal SIGHUP au PID identifié. Par exemple la commande suivant le permet :
    kill -SIGHUP <PID>
    Dès que le régulateur reçoit ce signal, il recharge le fichier de configuartion et prend en compte la ou les options modifiées.

Options.

Contrairement aux arguments, l'ordre des options sur la ligne de commande est sans importance.

En revanche, si un fichier de configuration est défini et qu'il est rechargé via le signal SIGHUP, l'ensemble des options qu'il contient est pris en compte quelle que soit les options définies sur la ligne de commande.

Le tableau qui suit précise l'ensemble des options disponibles et leur valeur par défaut.

    Abréviation Défaut Rôle
-h --help Aide   Affichage de l'aide au lancement du régulateur.
-v --version Aide   Affichage de la version du régulateur.
-s <0|1> --sim <0|1> Simulation 1 Mode simulation si "1", mode réel si "O". En mode simulation, la commande de délivrance de puissnace n'est pas transmise à la Venus mais simplement affichée. Notez que le mode par défaut est "simulation".
-i <entier> --id <entier> Identifiant 0 Identifiant numérique de la Venus lorsqu'il y en a plusieurs. S'il n'y a qu'une seule Venus sur le réseau cette valeur est toujours 0 (défaut).
-d <entier> --dod <entier> Deep Of Discharge 20 Il s'agit du pourcentage de charge de la batterie en dessous duquel, le régulateur interrompt ses demande de livraison d'énergie. Il devrait toujours être supérieur à celui définit par la Venus elle-même sinon l'énergie ne sera pas fournie mais vous n'en serez pas informé.
-w <entier> --pwm <entier> Power Max. 800

Limite de la puissance délivrée.

Jusqu'à la version 1.1.0, lorsque la puissance demandée est supérieure à cette valeur, elle y est ramenée.

A partir de la version 1.1.0, il est possible soit de fixer la puissance maximum sous forme d'une constante strictement positive avec un comportement identique aux versions précédentes.
Il est aussi possible d'associer à cette propriété, la valeur 0. Cela signifie que la puissance maximale est fonction de la capacité restante (SOC). Ainsi, la puissance maximale est donnée par la formule PMAX = SOC * 15. Ainsi, à 100% PMAX = 1500, à 80% PMAX = 1200, à 50% PMAX = 750 et à 30% PMAX = 450. L'idée est ici de prolonger au maximum la durée de founiture d'énergie par la batterie et ainsi favoriser l'effacement de la puissance "talon" au détriment des pointes de consommation.

En période estivale, la batterie se recharge très vite et peut donc absorber les pointes de consommation. Ce n'est plus le cas en période hivernale. Si on souhaite conserver un minimum de capacité pour faire face à une panne prolongée du secteur, il est indispensable d'éviter que les pointes de consommation ne vide trop rapidement la batterie.

-r <entier> --wtr <entier> Waiting To Recharge 30 Délai en minute d'interruption de la régulation lorsque le seuil de décharge de la batterie (DOD) est atteint. Ce devrait être le délai minimum pour que la batterie se recharge d'au moins un pourcent. De toute façon, si la charge n'a pas permit d'atteindre ce pourcent (absence de charge la nuit par exemple), l'attente de "wtr" minutes sera renouvelée et ainsi de suite jusqu'à ce que la batterie se soit un peu rechargée.
-g <entier> --rp <entier> Regulation Period 1000 Délai minimum en millisecondes entre deux commandes de régulation. Notez qu'en raison de l'emploi d'UDP qui supporte mal les collisions sur le réseau, le délai réel est souvent de l'ordre de 2 à 5 secondes (dépend de la qualité du réseau).
-p <entier> --pmt <entier> Passive Mode Timeout 10 Délai en secondes du maintien de chaque puissance commandée en mode passif.
-t <chaîne de caractères> --tme <chaîne de caractères> Times aucun Définition des créneaux au sein desquels la délivrance de puissance est autorisée. Si un ou plusieurs créneaux sont définis, aucune puissance ne sera délivrée en dehors de ces créneaux. Cela est pratique pour favoriser des moments privilégiés de consommation comme les heures pleines.
Un créneau est défini par une heure de début et une heure de fin. Ces deux horaires sont séparés par un tiret.
L'horaire eest défini par deux caractères par l'heure et deux caractères pour les minutes avec le double-point comme séparateur.
Les créneaux horaires sont séparés par des virgules.
Le chevauchement des créneaux est interdit.
Ainsi 00:00-03:00,06:00-22:00 indique que la puissance est délivrée de 6h à 22h puis de minuit à 3h du matin.
L'ordonnancement des créneaux horaires est sans importance.

Fichier de configuration (éventuel).

Le fichier de configuration est un fichier JSON dont les propriéts ont des noms identiques au format long des options :

{
    "sim": false,
    "tme": "00:00-03:00,06:00-23:59",
    "id": 0,
    "rp": 1000,
    "dod": 20,
    "wtr": 30,
    "pmt": 15,
    "pwm": 800
}

Les propriétés dans ce fichier sont toutes optionnelles. Au lancement, si elles n'apparaissent pas, c'est la valeur par défaut qui est prise en compte. Au rechargement, seules les options qui apparaissent dans le fichier sont prises en compte.

Suivi de la régulation.

Il est important que l'on puisse suivre à la demande le fonctionnement du régulateur. Pour cela, il émet les messages d'avertissement et d'erreur sur le flux standard des erreurs et les messages d'information sur le flux de sortie standard.

Comme le régulateur a pour vocation de travailler en tâche de fond, il est recommandé de rediriger ces flux dans un ou deux fichiers (un pour les avertissements/erreurs et un autre pour les messages d'information). Voici un exemple de redirection :

./jmpsolar 192.168.0.10:30000 http://192.168.0.11 /etc/jmpsolar.json 1>/var/log/jmps_out.log 2>/var/log/jmps_err.log

Si ces informations n'ont pas d'intérêt pour vous, il est possible de les rediriger ver /dev/null.

Voici un exemple des traces émises :

jmpsolar v1.0.4 (202610280838) : régulation de la production solaire
(c) Jean-Marie Piatte

Paramètres de la connexion UDP côté Venus .........: [192.168.0.10:30000]
URL de la connexion HTTP au wattmètre Shelly ......: http://192.168.0.11/rpc
Créneaux horairex de la régulation ................: 06:00-23:59
Simulation de la commande de régulation vers Venus : Non
Identifiant de la Venus sur le réseau .............: 0
Profondeur maximale de décharge de la batterie ....: 22 %
Puissance maximale délivrable par la Venus ........: 800 W
Délai d'attente pour une recharge minimale ........: 30 minutes
Période entre deux procédures de régulation .......: 100 millisecondes
Délai d'activation du mode passif .................: 15 secondes
Nom du fichier de configuration ...................: /etc/jmpsolar.json

[28/10/2026 08:42:38] Puissance intantanée retournée par le wattmètre : 229.806 W
[28/10/2026 08:42:38] Le wattmètre Shelly et la batterie Venus sont tous deux en ligne

[28/10/2026 08:42:38] puissance wattmètre = 229.806 W, puissance demandée = 229 W, durée = 15 s, décharge = 55 %
[28/10/2026 08:42:41] puissance wattmètre = 252.418 W, puissance demandée = 252 W, durée = 15 s, décharge = 55 %
[28/10/2026 08:42:44] puissance wattmètre = 241.387 W, puissance demandée = 241 W, durée = 15 s, décharge = 55 %
[28/10/2026 08:42:47] puissance wattmètre = 228.983 W, puissance demandée = 228 W, durée = 15 s, décharge = 55 %
[28/10/2026 08:42:50] puissance wattmètre = 243.156 W, puissance demandée = 243 W, durée = 15 s, décharge = 55 %
[28/10/2026 08:42:54] puissance wattmètre = 245.309 W, puissance demandée = 245 W, durée = 15 s, décharge = 55 %
[28/10/2026 08:42:57] puissance wattmètre = 231.443 W, puissance demandée = 231 W, durée = 15 s, décharge = 55 %
...

Lorsque vous rechargez le fichier de configuration à chaud via le signal SIGHUP ce rechargement apparait dans les traces sous la forme du réaffichage des arguments et des options prises en compte.

En mode simulation, seule la puissance lue auprès du wattmètre est affichée.

Voici un exemple des traces du fichier des erreurs :

[28/10/2026 09:09:46] [28/10/2026 09:09:54] Echec de la méthode UdpEngine::setPassiveMode : QString UdpEngine::sendAndListen(const QHostAddress&, quint16, const QString&) -> Pas de réponse UDP au bout de 1500 ms
[28/10/2026 09:11:12] [28/10/2026 09:11:21] Echec de la méthode UdpEngine::setPassiveMode : QString UdpEngine::sendAndListen(const QHostAddress&, quint16, const QString&) -> Pas de réponse UDP au bout de 1500 ms
[28/10/2026 10:21:16] [28/10/2026 10:21:24] Echec de la méthode UdpEngine::setPassiveMode : QString UdpEngine::sendAndListen(const QHostAddress&, quint16, const QString&) -> Pas de réponse UDP au bout de 1500 ms
[28/10/2026 10:31:00] [28/10/2026 10:31:10] Echec de la méthode UdpEngine::setPassiveMode : QString UdpEngine::sendAndListen(const QHostAddress&, quint16, const QString&) -> Pas de réponse UDP au bout de 1500 ms
[28/10/2026 10:31:10] [28/10/2026 10:31:54] Echec de la méthode UdpEngine::setPassiveMode : QString UdpEngine::sendAndListen(const QHostAddress&, quint16, const QString&) -> Pas de réponse UDP au bout de 1500 ms
[28/10/2026 10:39:40] [28/10/2026 10:39:49] Echec de la méthode UdpEngine::setPassiveMode : QString UdpEngine::sendAndListen(const QHostAddress&, quint16, const QString&) -> Pas de réponse UDP au bout de 1500 ms
[28/10/2026 10:44:13] [28/10/2026 10:44:21] Echec de la méthode UdpEngine::setPassiveMode : QString UdpEngine::sendAndListen(const QHostAddress&, quint16, const QString&) -> Pas de réponse UDP au bout de 1500 ms
[28/10/2026 11:11:07] [28/10/2026 11:11:15] Echec de la méthode UdpEngine::setPassiveMode : QString UdpEngine::sendAndListen(const QHostAddress&, quint16, const QString&) -> Pas de réponse UDP au bout de 1500 ms

Modes de lancement.

Comme le régulateur est un programme console traditionnel, il existe de multiples façons de le lancer. Pour abstraire l'architecture, on crée un lien symbolique nommé jmpsolar sur le véritable exécutable qui est soit jmpsolar-x86_64.AppImage, soit jmpsolar-aarch64.AppImage. Ainsi, dans les exemples qui suivent, jmpsolar référence le véritable exécutable.

Lancement manuel direct.

A partir d'un terminal, on peut directement le lancer en lui fixant ses options et surtout ses arguments. L'affichage des messages de suivi s'effectue sur le terminal.

L'inconvénient est que dès que l'on ferme le terminal, on ferme aussi ses processus enfants dont le régulateur. Cette solution n'est donc pas viable pour une régulation opérationnelle sur un temps long.

En revanche, elle peut être très utile pour le mode "simulation" qui permet de vérifier la présence de la Venus et du wattmètre sur le réseau tout en affichant périodiquement la puissance instantanée mesurée par le wattmètre.

Il est malgré tout possible de lancer le régulateur sans qu'il soit le processus enfant du terminal. Il suffit de le lancer via l'utilitaire setsid :

setsid ./jmpsolar 192.168.0.10:30000 http://192.168.0.11 /etc/jmpsolar.json 1>/var/log/out.log 2>/var/log/err.log &

Lancement via le cron au boot de la machine.

Même lancé en arrière-plan via la commande setsid, le régulateur n'est pas à l'abri d'une panne prolongée. Quel que soit le mode de lancement via un terminal, l'arrêt plus ou moins programmé de la machine ne relancera pas le régulateur dès que la machine sera de nouveau opérationnelle.

Un moyen facile de palier à cet inconvénienbt est de lancer le programme via le planificateur cron via l'instruction @reboot :

# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
@reboot root sleep 60 && setsid /usr/bin/jmpsolar 192.168.0.10:30000 http://192.168.0.11 /etc/jmpsolar.json 1>/var/log/out.log 2>/var/log/err.log
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6    * * 7   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6    1 * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
#

De cette manière, chaque fois que la machine se relance, le régulateur est lancé également. Notez que le régulateur se lance 1 minute après le boot. Ce démarrage différé garantit que le réseau est opérationnel lorsque le régulateur se lance. Cela suppose toutefois des droits d'administration associé au compte qui accéde au fichier /etc/crontab.

Lancement comme un service au boot de la machine.

C'est clairement la solution que nous recommandons pour un usage opérationnel du régulateur. Il suffit d’écrire un fichier d’unité (.service) décrivant comment lancer votre exécutable, puis de l’activer. Voici la démarche complète (utilisation des droits root).

  1. Placer l’exécutable dans un emplacement système.

    Nous recommandons /usr/local/bin ou /opt/jmpsolar. Pour cela placez-vous sur le répertoire qui contient votre exécutable puis tapez la commande

    install -m 755 ./jmpsolar-aarch64.AppImage /usr/local/bin/jmpsolar-aarch64.AppImage
    Cette commande recopie l'exécutable sur /usr/local/bin et luis affecte les droits "rwxr-xr-x" (755). Nous vous conseillons de créer un lien symbolique pour simplifier le nom de l'exécutable :
    ln -s /usr/local/bin/jmpsolar-aarch64.AppImage /usr/local/bin/jmpsolar

    ATTENTION : lorsqu'un service démarre, il vérifie les droits sur chaque répertoire traversé pour accéder au fichier à exécuter. La commande namei -l /usr/local/bin/jmpsolar permet de suivre les droits jusqu'à l'exécutable.

    Certains Linux dont Debian interdisent l'accès du répertoire d'un utilisateur (sous /home) aux autres comptes. C'est donc une très mauvaise idée au plan de la sécurité de placer l'exécutable lancé par le service avec le compte jmpsolar sur un répertoire utilisateur car cela vous oblige à ouvrir les droits au compte jmpsolar sur le compte de cet utilisateur.

  2. Créez /etc/systemd/system/jmpsolar.service.

    Ce fichier comporte les informations suivantes :

    [Unit]
    Description=jmpsolar
    # Attendre que le réseau soit réellement configuré (utile car l'application ouvre des sockets)
    Wants=network-online.target
    After=network-online.target
    
    [Service]
    Type=exec
    ExecStart=/usr/local/bin/jmpsolar 192.168.0.10:30000 http://192.168.0.11 /etc/jmpsolar.json
    StandardOutput=append:/var/log/jmpsolar/jmpsolar.log
    StandardError=append:/var/log/jmpsolar/jmpsolar.err
    WorkingDirectory=/var/lib/jmpsolar
    # Compte non privilégié (à créer, voir plus bas)
    User=jmpsolar
    Group=jmpsolar
    # Redémarrage automatique en cas de plantage
    Restart=on-failure
    RestartSec=5
    # Variables d'environnement éventuelles
    Environment=
    
    [Install]
    WantedBy=multi-user.target
  3. Créer l’utilisateur dédié (recommandé).

    Cela se fait via les commandes :

    sudo useradd --system --no-create-home --shell /usr/sbin/nologin jmpsolar
    sudo mkdir -p /var/lib/jmpsolar
    sudo chown jmpsolar:jmpsolar /var/lib/jmpsolar

    Assurez vous que le nouveau compte jmpsolar à accès en lecture/écriture au répertoire /var/log/jmpsolar.

    Une alternative plus simple consiste à ajouter DynamicUser=yes et StateDirectory=jmpsolar dans [Service]. systemd crée alors l’utilisateur à la volée, ainsi que /var/lib/jmpsolar.

  4. Activer et démarrer le service.

    sudo systemctl daemon-reload            # relire les unités
    sudo systemctl enable --now jmpsolar    # activer au boot + démarrer tout de suite
  5. Surveiller l'activité du régulateur.

    Si vous ne définsissez pas les propriétés StandardOutput et StandardError les messages de sortie sont dirigés dans le journal du système. Les commandes qui suivent permettent de les consulter.

    systemctl status jmpsolar
    journalctl -u jmpsolar -f               # logs en direct
    journalctl -u jmpsolar -b               # logs depuis le dernier boot
  6. Si vous avez définis la redirection de la sortie standard et du flux d'erreur vers des fichiers via les propriétés StandardOutput et StandardError, les messages sont consultables via n'importe quel éditeur de texte ou par des commandes du shell comme par exemple :

    tail -30 /var/log/jmpsolar/jmpsolar.log
    tail -30 /var/log/jmpsolar/jmpsolar.err

    Ces commandes affichent sur la console les 30 dernières lignes de chacun des fichiers.

Notez que dans le fichier de service proposé nous avons opté pour la définition des propriétés StandardOutput et StandardError. En effet, le régulateur est assez verbeux et "encombrer" le journal système de ces messages n'est pas très judicieux.

Pensez après toute modification du fichier (.service) à taper la commande daemon-reload puis systemctl restart jmpsolar.

Il est possible de fixer les arguments de l'exécutable dans un fichier externe de façon à ne pas modifier le fichier du service mais cela sort du cadre de cette documentation.