fabian-lauer / dbus-shelly-3em-smartmeter

Integrate Shelly 3EM smart meter into Victron Energies Venus OS
125 stars 55 forks source link

Robustness regarding non reachable meters #11

Closed mpolak77 closed 1 year ago

mpolak77 commented 1 year ago

Short story: I think the script should set current power meter values to 0, whenever the meter is not reachable.

Long story: I'm running the latest version with my Multiplus II and Venus on a raspberry pi.

Recently I've discovered my inverter pushing max power into L1, while the actual load only was around 300-500W. As a root cause I could find a broken Wifi connection to the shelly device, the log did show a long list of exceptions. Multiplus would still see a usage of 500 W and would push up power for compensating that ..... the meter value would not get back to Multiplus accordingly, and Multiplus increased even more. If a missing meter fetch attempt would have set values to 0, this would at least have prevented Multiplus from trying to compensating and emptying the battery.

fabian-lauer commented 1 year ago

HI @mpolak77 ,

thanks for the feedback - I agree, error handling is not the best - had a similar problem a few weeks ago. But unfortunately I am missing a little bit of time to do so....

Would be happy for some support - proposals, code-snippets, etc..

Thx

mpolak77 commented 1 year ago

Here a first attempt which seems to work, and also prints exceptions more readable:


--- dbus-shelly-3em-smartmeter-master.py
+++ dbus-shelly-3em-smartmeter.py
@@ -104,7 +104,7 @@

   def _getShellyData(self):
     URL = self._getShellyStatusUrl()
-    meter_r = requests.get(url = URL)
+    meter_r = requests.get(url = URL, timeout=5)

     # check for response
     if not meter_r:

@@ -158,14 +156,20 @@
        logging.debug("House Reverse (/Ac/Energy/Revers): %s" % (self._dbusservice['/Ac/Energy/Reverse']))
        logging.debug("---");

-       # increment UpdateIndex - to show that new data is available
-       index = self._dbusservice['/UpdateIndex'] + 1  # increment index
-       if index > 255:   # maximum value of the index
-         index = 0       # overflow from 255 to 0
-       self._dbusservice['/UpdateIndex'] = index
+       # increment UpdateIndex - to show that new data is available an wrap
+       self._dbusservice['/UpdateIndex'] = (self._dbusservice['/UpdateIndex'] + 1 ) % 256

        #update lastupdate vars
        self._lastUpdate = time.time()              
+ 
+    except (ValueError, requests.exceptions.ConnectionError, requests.exceptions.Timeout, ConnectionError):
+       logging.critical('Error getting data from Shelly - check network or Shelly status. Setting power values to 0')
+       self._dbusservice['/Ac/L1/Power'] = 0                                       
+       self._dbusservice['/Ac/L2/Power'] = 0                                       
+       self._dbusservice['/Ac/L3/Power'] = 0
+       self._dbusservice['/Ac/Power'] = 0
+       self._dbusservice['/UpdateIndex'] = (self._dbusservice['/UpdateIndex'] + 1 ) % 256                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
+             
     except Exception as e:
        logging.critical('Error at %s', '_update', exc_info=e)

@@ -233,7 +237,12 @@
       logging.info('Connected to dbus, and switching over to gobject.MainLoop() (= event based)')
       mainloop = gobject.MainLoop()
       mainloop.run()            
+   
+  except (ValueError, requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e:
+    logging.critical('Error in main type %s', str(e))
+
   except Exception as e:
     logging.critical('Error at %s', 'main', exc_info=e)
+
 if __name__ == "__main__"
```:
mascheihei commented 1 year ago

@mpolak77 Good idea, but only works if the gridpower set point is 0 Watt. It would be better to set it to "/Settings/Cgwacs/AcPowerSetPoint". Then it is aligned to target of ESS control loop. Another point: If the json decoding fails -> is this catched by ValueError? or should we add requests.exceptions.JSONDecodeError

mpolak77 commented 1 year ago

Good point - just realized that Multiplus starts to charge, if SetPoiint is >0 and Meter reads 0 …. Now I need to find out, how to do this correctly depending on 1phase vs all phase Saldo mode.

fabian-lauer commented 1 year ago

@mpolak77 thank you for your input - will add that to the next commit

fabian-lauer commented 1 year ago

Should be all in now. Thanks for the input