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 no accessible to you, you can download the driver 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/d0b25d27-1aa1-466a-9c34-a5ded5dc728a%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)

Reply via email to