Hello, Here is a driver for the Ambient Weather ObserverIP box, based on Pat O'Brien's driver, which is based on Tom Keffer's driver. It uses the "scraping" technique, but does not suffer from any instability, crashes, or hangs. Also, it does not require you to do anything special to your router or internet set-up. The secret of its success s that it reboots the ObserverIP every 24 hours. I have been running it for almost a year, with no crashes or other problems.
You can see it in action at: http://dougbert.is-a-geek.com:8080/weewx/index.html If the attachment is not accessible to you, you can download the code from: http://dougbraun.com/software/observerip_scraper_py.txt -- You received this message because you are subscribed to the Google Groups "weewx-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/weewx-user/d5422623-2195-4c28-871d-cc52dfd2888d%40googlegroups.com.
# $Id: pobwx.py 2766 2014-12-02 02:45:36Z tkeffer $ # Copyright (c) 2012 Tom Keffer <[email protected]> # See the file LICENSE.txt for your full rights. """ weewx Driver for the Ambient Weather ObserverIP, based on scraping Pat O'Brien https://github.com/poblabs/weewx-ObserverIP """ from __future__ import with_statement from lxml import html import math, time, syslog, requests import weedb import weewx.drivers import weeutil.weeutil import weewx.wxformulas DRIVER_NAME = 'ObserverIP_scraper' DRIVER_VERSION = '1.0' def loader(config_dict, engine): station = ObserverIP_scraper(**config_dict['ObserverIP_scraper']) return station # Convert stuff like "---" to None, like weewx expects. def dataToFloat(value): try: return float(value) except: return None class ObserverIP_scraper(weewx.drivers.AbstractDevice): """Custom driver for Ambient Weather ObserverIP, based on scraping Mostly based off Simulator """ def __init__(self, **stn_dict): self.loop_interval = float(stn_dict.get('loop_interval')) # This is how many reads should be done between each reboot, # to get a reboot every 24 hours. self.reboot_interval = 24 * 60 * 60 / self.loop_interval # Seconds to wait after sending reboot command. self.reboot_delay = 30 self.reads_since_reboot = 0 self.success_count = 0 self.station_ip = stn_dict.get('ip_address') self.station_url = "http://%s/livedata.htm" % self.station_ip self.reboot_url = "http://%s/msgreboot.htm" % self.station_ip self.station_hardware = stn_dict.get('hardware') self.last_rain = None def getTime(self): # The ObserverIP doesn't do seconds, so using the time from the ObserverIP # with a loop packet of every 15 seconds is useless. All measurements will be archived # from the same minute timestamp, even though the values could be different within the same minute. # This method uses mwall's method from his fork of ObserverIP epoch = int(time.time() + 0.5 ) return epoch def hardware_name(self): return self.station_hardware def get_battery_status(self, data): if (data == "Normal"): return 0 else: return 1 def rain_delta(self, rain_total): # Handle the rain accum by taking the accumulated rain reading and only submitting the increments delta = weewx.wxformulas.calculate_rain(rain_total, self.last_rain) self.last_rain = rain_total return delta def rebootObserverIP(self): syslog.syslog("Rebooting ObserverIP") # Touch the ObserverIP reboot URL to cause it to reboot. try: page = requests.get(self.reboot_url, timeout=15.0) page.raise_for_status() except Exception as e: syslog.syslog("ObserverIP_scraper driver couldn't access %s." % self.reboot_url) syslog.syslog("Error caught was: %s" % e) syslog.syslog("Sleeping for %s" % self.reboot_delay) time.sleep(self.reboot_delay) def genLoopPackets(self): while True: # Screen scrape the ObserverIP to get sensor readings. try: page = requests.get(self.station_url, timeout=15.0) page.raise_for_status() tree = html.fromstring(page.content) # Can weewx take this value? #uvi = tree.xpath('//input[@name="uvi"]')[0].value inBattery = tree.xpath('//input[@name="inBattSta"]')[0].value outBattery = tree.xpath('//input[@name="outBattSta1"]')[0].value inTemp = tree.xpath('//input[@name="inTemp"]')[0].value inHumid = tree.xpath('//input[@name="inHumi"]')[0].value outTemp = tree.xpath('//input[@name="outTemp"]')[0].value outHumid = tree.xpath('//input[@name="outHumi"]')[0].value absPressure = tree.xpath('//input[@name="AbsPress"]')[0].value relPressure = tree.xpath('//input[@name="RelPress"]')[0].value windDir = tree.xpath('//input[@name="windir"]')[0].value windSpeed = tree.xpath('//input[@name="avgwind"]')[0].value windGust = tree.xpath('//input[@name="gustspeed"]')[0].value solarRadiation = tree.xpath('//input[@name="solarrad"]')[0].value uv = tree.xpath('//input[@name="uv"]')[0].value dayRain = tree.xpath('//input[@name="rainofdaily"]')[0].value monthRain = tree.xpath('//input[@name="rainofmonthly"]')[0].value yearRain = tree.xpath('//input[@name="rainofyearly"]')[0].value self.success_count += 1 except Exception as e: syslog.syslog("ObserverIP_scraper driver couldn't access %s." % self.station_url) syslog.syslog("Error caught was: %s" % e) syslog.syslog("%d successful reads since last error" % self.success_count) self.success_count = 0 pass # Continue without exiting. TODO: Better error handling and error sleeping # Build the packet data try: _packet = { 'dateTime' : self.getTime(), 'usUnits' : weewx.US, 'outTemp' : dataToFloat(outTemp), 'outHumidity' : dataToFloat(outHumid), 'inTemp' : dataToFloat(inTemp), 'inHumidity' : dataToFloat(inHumid), 'pressure' : dataToFloat(absPressure), 'barometer' : dataToFloat(relPressure), 'rain': self.rain_delta(dataToFloat(yearRain)), # weewx can calculate the per-period rain totals #'dayRain' : dataToFloat(dayRain), #'monthRain' : dataToFloat(monthRain), #'yearRain' : dataToFloat(yearRain), 'windDir' : dataToFloat(windDir), 'windSpeed' : dataToFloat(windSpeed), 'windGust' : dataToFloat(windGust), # WS-0900 does not support these. The fields are "----.-" #'radiation' : float(solarRadiation), #'UV' : float(uv), 'outTempBatteryStatus' : self.get_battery_status(outBattery), 'inTempBatteryStatus' : self.get_battery_status(inBattery) } yield _packet except Exception as e: syslog.syslog("ObserverIP_scraper driver had an error yielding data packet to weewx.") syslog.syslog("Error caught was: %s" % e) pass # Continue without exiting. TODO: Better error handling and error sleeping # If the time is right, reboot the ObserverIP self.reads_since_reboot += 1 if (self.reads_since_reboot > self.reboot_interval): self.rebootObserverIP() self.reads_since_reboot = 0 # Sleep time #syslog.syslog("Sleeping for %s" % self.loop_interval) time.sleep(self.loop_interval)
