> ## Documentation Index
> Fetch the complete documentation index at: https://helpdesk.simply-offgrid.nl/llms.txt
> Use this file to discover all available pages before exploring further.

# Shelly Pro EM-50 als PV-omvormer uitlezen op de Cerbo GX

> De Cerbo ziet de Shelly Pro EM-50 standaard alleen als schakelaar, zonder PV-opbrengst. Met een klein driver-script lees je de zonne-opbrengst tóch uit als volwaardige PV-omvormer. Voor gevorderde gebruikers.

<Warning>
  **Technische handleiding — alleen voor gevorderde gebruikers.** Deze procedure
  veredert de Cerbo GX via SSH, een root-wachtwoord en een zelf toegevoegd
  Python-driver-script. Dit is **geen officiële Victron- of Shelly-functie** maar een
  community-oplossing. Weet je niet zeker wat SSH, `nano` of een DBus-service is? Doe
  dit dan niet zelf — [mail ons](mailto:support@simply-offgrid.nl), dan kijken we mee.
  Uitvoeren op eigen risico.
</Warning>

## Waarom dit nodig is

De Shelly Pro EM-50 heeft twee energiemeet-kanalen én een ingebouwde schakelaar
(relais). Venus OS (ook v3.70+ met de ingebouwde Shelly-integratie) koppelt het
apparaat daardoor onder de **schakelaars/relais**, niet als PV-omvormer. Je ziet de
Shelly dus wel in de apparatenlijst staan, maar je **PV-opbrengst komt niet in het
overzicht of in VRM** terecht.

De ingebouwde integratie kan de meetkanalen (nog) niet als PV-inverter presenteren.
De oplossing: we lezen de Shelly rechtstreeks uit via zijn HTTP-API en publiceren de
waarden zelf als PV-omvormer op de DBus van de Cerbo.

<Note>
  De Pro EM-50 gebruikt het nieuwere **Gen2/Gen3 RPC-protocol**
  (`/rpc/Shelly.GetStatus`), met de meetdata onder `em1:0` en `em1:1`. Kant-en-klare
  `dbus-shelly`-scripts die de oude Gen1-API (`/status`) of de `switch:0`-structuur
  verwachten, werken daaróm niet zonder aanpassing. Het script hieronder is specifiek
  op de Pro EM-50 afgestemd.
</Note>

## Wat je nodig hebt

* Een **Cerbo GX** (of ander GX-apparaat) met Venus OS.
* De Shelly Pro EM-50 aan hetzelfde netwerk, met een **vast IP-adres** (reserveer het in je router).
* **Geen wachtwoordbeveiliging** op de Shelly (of noteer de inloggegevens — je vult ze straks in de config in).
* Een computer met een **terminal** (Terminal op macOS/Linux, of PuTTY / `cmd` op Windows).
* Het IP-adres van je Cerbo én van je Shelly.

## Stap 1 — Zet de ingebouwde Shelly-integratie uit

Anders "bezet" de native integratie het apparaat als schakelaar en botst dat met de
PV-omvormer die je zo aanmaakt.

<Steps>
  <Step title="Open de integratie-instellingen">
    Ga op de Cerbo (of Remote Console) naar **Instellingen → Integraties → Shelly**
    (afhankelijk van je firmware ook onder Modbus/netwerkapparaten).
  </Step>

  <Step title="Schakel de Shelly uit">
    Zoek je Shelly Pro EM-50 in de lijst en zet hem op **Uitgeschakeld** (of kies
    **Vergeten / verwijderen** als die optie er staat).
  </Step>
</Steps>

## Stap 2 — Zet root-toegang en SSH aan

<Tabs>
  <Tab title="Nieuwe interface (GUI-v2)">
    1. Ga naar **Instellingen → Toegang en beveiliging**.
    2. Trek de hele lijst naar beneden en **houd \~5 seconden vast** — het
       toegangsniveau springt naar **Superuser**.
    3. Er verschijnen onderaan twee nieuwe regels: **Root-wachtwoord instellen** en
       **SSH via lokaal netwerk (LAN)**. Stel een wachtwoord in en zet SSH aan.
  </Tab>

  <Tab title="Klassieke interface (GUI-v1)">
    1. Ga naar **Settings → General**.
    2. Zet **Access Level** op **Superuser** (houd op *Access Level* de pijl-rechts
       ingedrukt tot Superuser verschijnt).
    3. Stel een **Root Password** in en zet **SSH on LAN** op **Enabled**.
  </Tab>
</Tabs>

<Tip>
  Zit je in GUI-v2 en lukt het gebaar niet? Schakel tijdelijk terug via **Instellingen
  → Display & taal → GUI-v1**, zet daar SSH aan, en switch daarna weer terug. De
  SSH-toegang blijft aan op de achtergrond.
</Tip>

## Stap 3 — Log in op de Cerbo via SSH

Open een terminal en verbind (vervang het IP door dat van jouw Cerbo):

```bash theme={null}
ssh root@192.168.0.185
```

Vraagt hij naar een "fingerprint"? Typ `yes`. Vul daarna je root-wachtwoord in (je
ziet tijdens het typen geen tekens verschijnen — dat is normaal). Je bent ingelogd als
je de prompt `root@einstein:~#` ziet (de naam wijkt af per systeem).

## Stap 4 — Installeer de driver-basis

We gebruiken een bestaande `dbus-shelly`-driver als "geraamte" (voor de service- en
herstart-scripts) en vervangen daarna het uitlees-script door een Pro EM-50-versie.
Plak dit blok in de terminal:

```bash theme={null}
cd /data
wget https://github.com/zandervalle/dbus-shelly-plus-pvinverter/archive/refs/heads/main.zip -O shelly.zip
unzip shelly.zip
mv dbus-shelly-plus-pvinverter-main dbus-shelly-plus-pvinverter
rm shelly.zip
chmod a+x /data/dbus-shelly-plus-pvinverter/install.sh
```

<Note>
  Community-repositories verhuizen of verdwijnen soms. Krijg je een `404`? Zoek dan op
  een actuele `dbus-shelly` PV-inverter driver — het geraamte (`install.sh`,
  `restart.sh`, `service/run`, `config.ini`) is generiek. Het **uitlees-script** uit
  stap 6 is het enige dat écht Pro EM-50-specifiek is.
</Note>

## Stap 5 — Vul het IP-adres in (config.ini)

```bash theme={null}
nano /data/dbus-shelly-plus-pvinverter/config.ini
```

Zet de inhoud zo (vul jouw Shelly-IP in bij `Host`):

```ini theme={null}
[DEFAULT]
AccessType = OnPremise
ProductName = Shelly Pro EM-50
DeviceInstance = 50
CustomName = Zonnepanelen
Phase = L1

[ONPREMISE]
Host = 192.168.0.171
UseAutentication = false
Username =
Password =
```

Heeft je Shelly wél een wachtwoord? Zet `UseAutentication = true` en vul `Username` en
`Password` in. Opslaan met **Ctrl + O → Enter**, sluiten met **Ctrl + X**.

<Tip>
  **DeviceInstance** moet uniek zijn op de DBus. Zag de Cerbo de Shelly eerder al onder
  een bepaald nummer (bijv. 40 of 50)? Kies dan een vrij nummer of hetzelfde nummer,
  zolang geen ander apparaat het al gebruikt.
</Tip>

## Stap 6 — Plaats het Pro EM-50 uitlees-script

Dit script leest **beide** meetkanalen (`em1:0` en `em1:1`), telt ze op tot één
PV-omvormer op fase L1, en haalt de energie (kWh) uit `em1data:0` / `em1data:1`. Maak
het bestand eerst leeg en open het:

```bash theme={null}
> /data/dbus-shelly-plus-pvinverter/dbus-shelly-plus-pvinverter.py
nano /data/dbus-shelly-plus-pvinverter/dbus-shelly-plus-pvinverter.py
```

Plak de volledige inhoud hieronder erin (let op: in Python is de inspringing met
spaties belangrijk — plak het in één keer):

<Accordion title="Volledig script: dbus-shelly-plus-pvinverter.py (beide kanalen → L1)">
  ```python theme={null}
  import os
  import sys
  import logging
  import configparser
  import requests
  from requests.auth import HTTPDigestAuth

  sys.path.insert(1, os.path.join(os.path.dirname(__file__), '/opt/victronenergy/dbus-systemcalc-py/ext/velib_python'))
  from vedbus import VeDbusService
  from gi.repository import GLib


  class DbusShellyPlusService:
      def __init__(self, servicename, deviceinstance, paths, productname='Shelly Pro EM-50', customname='Zonnepanelen'):
          self._dbusservice = VeDbusService(servicename)
          self._paths = paths

          logging.debug("%s /DeviceInstance = %d" % (servicename, deviceinstance))

          self._dbusservice.add_path('/Mgmt/ProcessName', __file__)
          self._dbusservice.add_path('/Mgmt/ProcessVersion', '1.0-ProEM50-DualL1')
          self._dbusservice.add_path('/Mgmt/Connection', 'Shelly Pro EM-50 HTTP RPC')

          self._dbusservice.add_path('/DeviceInstance', deviceinstance)
          self._dbusservice.add_path('/ProductId', 0xFFFF)
          self._dbusservice.add_path('/ProductName', productname)
          self._dbusservice.add_path('/CustomName', customname)
          self._dbusservice.add_path('/Connected', 1)

          self._dbusservice.add_path('/Latency', None)
          self._dbusservice.add_path('/Role', 'pvinverter')
          self._dbusservice.add_path('/Position', 0)

          for path, settings in self._paths.items():
              self._dbusservice.add_path(
                  path, settings['initial'], gettextcallback=settings['gettextcallback'], writeable=True, onchangecallback=self._handlechangedvalue
              )

          GLib.timeout_add(1000, self._update)

      def _getShellyData(self):
          config = self._getConfig()
          URL = f"http://{config['ONPREMISE']['Host']}/rpc/Shelly.GetStatus"

          if config['ONPREMISE']['UseAutentication'] == 'true':
              meter_r = requests.get(url=URL, auth=HTTPDigestAuth(config['ONPREMISE']['Username'], config['ONPREMISE']['Password']), timeout=5)
          else:
              meter_r = requests.get(url=URL, timeout=5)

          if not meter_r:
              raise ConnectionError("No response from Shelly - %s" % (URL))

          return meter_r.json()

      def _getConfig(self):
          config = configparser.ConfigParser()
          config.read(f"{os.path.dirname(os.path.realpath(__file__))}/config.ini")
          return config

      def _handlechangedvalue(self, path, value):
          return True

      def _update(self):
          try:
              meter_data = self._getShellyData()

              # Kanaal em1:0
              p0 = float(meter_data['em1:0']['act_power']) if 'em1:0' in meter_data else 0.0
              v0 = float(meter_data['em1:0']['voltage']) if 'em1:0' in meter_data else 0.0
              i0 = float(meter_data['em1:0']['current']) if 'em1:0' in meter_data else 0.0

              # Kanaal em1:1
              p1 = float(meter_data['em1:1']['act_power']) if 'em1:1' in meter_data else 0.0
              v1 = float(meter_data['em1:1']['voltage']) if 'em1:1' in meter_data else 0.0
              i1 = float(meter_data['em1:1']['current']) if 'em1:1' in meter_data else 0.0

              # Optellen tot één omvormer op L1
              power = p0 + p1
              current = i0 + i1
              voltage = v0 if v0 > 0 else v1

              # Energie (kWh) optellen
              e0 = float(meter_data['em1data:0']['total_act_energy']) / 1000.0 if ('em1data:0' in meter_data and 'total_act_energy' in meter_data['em1data:0']) else 0.0
              e1 = float(meter_data['em1data:1']['total_act_energy']) / 1000.0 if ('em1data:1' in meter_data and 'total_act_energy' in meter_data['em1data:1']) else 0.0
              total_energy = e0 + e1

              self._dbusservice['/Ac/L1/Voltage'] = voltage
              self._dbusservice['/Ac/L1/Current'] = current
              self._dbusservice['/Ac/L1/Power'] = power
              if power > 0:
                  self._dbusservice['/Ac/L1/Energy/Forward'] = total_energy

              for phase in ['L2', 'L3']:
                  pre = '/Ac/' + phase
                  self._dbusservice[pre + '/Voltage'] = 0
                  self._dbusservice[pre + '/Current'] = 0
                  self._dbusservice[pre + '/Power'] = 0

              self._dbusservice['/Ac/Power'] = power
              self._dbusservice['/Ac/MaxPower'] = 10000
              self._dbusservice['/Ac/Energy/Forward'] = total_energy

              logging.debug(f"Shelly Pro EM-50 Total: {power}W ({p0}W + {p1}W)")

          except Exception as e:
              logging.critical(f"Error at _update: {e}")

          return True


  def main():
      logging.basicConfig(filename=f"{os.path.dirname(os.path.realpath(__file__))}/current.log", level=logging.DEBUG)

      config = configparser.ConfigParser()
      config.read(f"{os.path.dirname(os.path.realpath(__file__))}/config.ini")

      paths_dbus = {
          '/Ac/Power': {'initial': 0, 'gettextcallback': lambda p, v: "{:.0f}W".format(v)},
          '/Ac/MaxPower': {'initial': 10000, 'gettextcallback': lambda p, v: "{:.0f}W".format(v)},
          '/Ac/Energy/Forward': {'initial': 0, 'gettextcallback': lambda p, v: "{:.2f}kWh".format(v)},

          '/Ac/L1/Voltage': {'initial': 0, 'gettextcallback': lambda p, v: "{:.1f}V".format(v)},
          '/Ac/L1/Current': {'initial': 0, 'gettextcallback': lambda p, v: "{:.1f}A".format(v)},
          '/Ac/L1/Power': {'initial': 0, 'gettextcallback': lambda p, v: "{:.0f}W".format(v)},
          '/Ac/L1/Energy/Forward': {'initial': 0, 'gettextcallback': lambda p, v: "{:.2f}kWh".format(v)},

          '/Ac/L2/Voltage': {'initial': 0, 'gettextcallback': lambda p, v: "{:.1f}V".format(v)},
          '/Ac/L2/Current': {'initial': 0, 'gettextcallback': lambda p, v: "{:.1f}A".format(v)},
          '/Ac/L2/Power': {'initial': 0, 'gettextcallback': lambda p, v: "{:.0f}W".format(v)},
          '/Ac/L2/Energy/Forward': {'initial': 0, 'gettextcallback': lambda p, v: "{:.2f}kWh".format(v)},

          '/Ac/L3/Voltage': {'initial': 0, 'gettextcallback': lambda p, v: "{:.1f}V".format(v)},
          '/Ac/L3/Current': {'initial': 0, 'gettextcallback': lambda p, v: "{:.1f}A".format(v)},
          '/Ac/L3/Power': {'initial': 0, 'gettextcallback': lambda p, v: "{:.0f}W".format(v)},
          '/Ac/L3/Energy/Forward': {'initial': 0, 'gettextcallback': lambda p, v: "{:.2f}kWh".format(v)},
      }

      from dbus.mainloop.glib import DBusGMainLoop
      DBusGMainLoop(set_as_default=True)

      DbusShellyPlusService(
          servicename='com.victronenergy.pvinverter.http_50',
          deviceinstance=50,
          paths=paths_dbus,
          productname=config['DEFAULT'].get('ProductName', 'Shelly Pro EM-50'),
          customname=config['DEFAULT'].get('CustomName', 'Zonnepanelen')
      )

      mainloop = GLib.MainLoop()
      mainloop.run()


  if __name__ == "__main__":
      main()
  ```
</Accordion>

Opslaan met **Ctrl + O → Enter**, sluiten met **Ctrl + X**.

<Note>
  Meet je met de twee kanalen twee **verschillende fasen** (bijv. L1 en L2) in plaats
  van twee groepen op dezelfde fase? Dan wil je ze niet optellen op L1, maar apart per
  fase publiceren. Neem in dat geval contact op — dan sturen we een variant van het
  script mee.
</Note>

## Stap 7 — Installeren, starten en controleren

```bash theme={null}
/data/dbus-shelly-plus-pvinverter/install.sh
pkill -f dbus-shelly-plus-pvinverter
rm -rf /data/dbus-shelly-plus-pvinverter/__pycache__
/data/dbus-shelly-plus-pvinverter/restart.sh
```

Bekijk daarna het live-logboek:

```bash theme={null}
tail -n 20 /data/dbus-shelly-plus-pvinverter/current.log
```

Zie je regels als `Shelly Pro EM-50 Total: 2601.6W (1012.4W + 1589.2W)` zonder
`CRITICAL`-fouten? Dan werkt het. Op het overzichtsscherm van de Cerbo en in VRM
verschijnt nu je zonne-opbrengst als PV-omvormer. Eventueel de Cerbo herstarten met
`reboot` om het overzicht direct te verversen.

## Handige controle: welke velden gebruikt jouw Shelly?

Twijfel je over de veldnamen (bij een ander Shelly-model of firmware)? Vraag de
statusregel rechtstreeks op:

```bash theme={null}
curl -s http://192.168.0.171/rpc/Shelly.GetStatus | grep -o '"em1:0":{[^}]*}'
```

Je ziet dan bijvoorbeeld:

```json theme={null}
"em1:0":{"id":0,"current":3.810,"voltage":241.8,"act_power":921.6,"aprt_power":923.2,"pf":0.99,"freq":50.0}
```

De Pro EM-50 gebruikt dus `act_power`, `voltage` en `current` — precies de velden die
het script uitleest.

## Problemen oplossen

| Melding in `current.log`                       | Oorzaak                                               | Oplossing                                                                         |
| ---------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------- |
| `ConnectionError: No response from Shelly`     | Verkeerd IP of Shelly niet bereikbaar                 | Controleer `Host` in `config.ini` en of de Shelly online is                       |
| `KeyError: 'apower'` of `KeyError: 'switch:0'` | Oud Gen1-/switch-script actief                        | Gebruik het script uit stap 6 (leest `em1:0`) en wis `__pycache__`                |
| PV-omvormer verdwijnt uit het overzicht        | Script crasht bij opstart (vaak inspring-/spatiefout) | `python3 .../dbus-shelly-plus-pvinverter.py` handmatig starten om de fout te zien |
| Blijft als **schakelaar** staan                | Ingebouwde Shelly-integratie nog actief               | Herhaal stap 1 en herstart de Cerbo                                               |

<Note>
  Dit is een handmatige aanpassing in `/data`. Die blijft doorgaans behouden bij een
  firmware-update, maar controleer na een grote Venus OS-update of de PV-omvormer nog
  in beeld is en of de ingebouwde Shelly-integratie het apparaat niet opnieuw als
  schakelaar heeft opgepakt.
</Note>

***

<CardGroup cols={2}>
  <Card title="Toegang geven tot VRM" icon="unlock" href="/support/vrm/vrm-toegang-geven">
    Laat onze support op afstand meekijken en instellingen aanpassen.
  </Card>

  <Card title="Contact & advies" icon="message" href="/orders/contact">
    Kom je er niet uit? Neem contact op — we helpen kosteloos op afstand.
  </Card>
</CardGroup>
