How can we help?


RainMachine and Davis Weather Stations

Comments

37 comments

  • Avatar
    Noopara

    Here it is...

    # Copyright (c) 2014 RainMachine, Green Electronics LLC
    # All rights reserved.
    # Authors: Nicu Pavel <npavel@mini-box.com>
    # Interval set to 1 hour. Anything less is not effective as RM Mixer runs on hourly interval

    from RMParserFramework.rmParser import RMParser
    from RMUtilsFramework.rmLogging import log
    from RMDataFramework.rmWeatherData import RMWeatherConditions
    from RMDataFramework.rmUserSettings import globalSettings
    from RMUtilsFramework.rmTimeUtils import *
    from RMUtilsFramework.rmUtils import convertKnotsToMS, convertFahrenheitToCelsius, convertInchesToMM

    import datetime, time
    import socket
    import struct
    import binascii

    class WeatherLinkIP(RMParser):
    parserName = "DavisWeatherLinkIP Parser"
    parserDescription = "Davis Weather Station with WeatherLink IP (local network access)"
    parserForecast = False
    parserHistorical = True
    parserEnabled = True
    parserDebug = False
    parserInterval = 1 * 3600
    params = {
    "stationAddress": "192.168.xxx.yyy",
    "stationPort": 22222,
    "useSolarRadiation": True,
    "useStationEvapoTranpiration": True
    }

    def isEnabledForLocation(self, timezone, lat, long):
    if WeatherLinkIP.parserEnabled:
    address = self.params.get("stationAddress", None)
    return address is not None
    return False


    def perform(self):
    s = self.settings
    address = self.getParamAsString(self.params.get("stationAddress"))
    port = self.params.get("stationPort", 22222)

    if address is None:
    self.lastKnownError = "No Station IP address specified"
    log.error(self.lastKnownError)
    return False

    try:
    wlsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    wlsocket.connect((address, port))
    wlsocket.settimeout(5)
    wlsocket.sendall(b"LOOP 1\n")
    log.info("Sent LOOP command")
    except Exception:
    self.lastKnownError = "Cannot connect to station IP: %s port %s." % (address, port)
    log.error(self.lastKnownError)
    return False

    retries = 5
    while retries > 0:
    try:
    raw_data = wlsocket.recv(1024)
    except socket.timeout, e:
    log.info("Recv timeout (%s) retrying." % e)
    time.sleep(2)
    wlsocket.sendall(b"LOOP 1\n")
    log.info("Sent LOOP command")
    retries -= 1
    continue
    except socket.error, e:
    log.info("Recv error (%s)." % e)
    self.lastKnownError = "No response from station"
    break
    else:
    log.info("Parsing Response")
    self.parsePacket(raw_data)
    break

    wlsocket.close()

    if self.parserDebug:
    log.info(self.result)


    #-----------------------------------------------------------------------------------------------
    #
    # Parse LOOP data.
    #
    def parsePacket(self, raw_data):
    self.lastKnownError = ""
    if raw_data is None or len(raw_data) < 99:
    self.lastKnownError = "Invalid data response"
    return False

    timestamp = rmCurrentTimestamp()
    if self.parserDebug:
    hex_string = binascii.hexlify(raw_data).decode('utf-8')
    log.info("Raw Data LOOP %s" % hex_string)
    try:
    ack = struct.unpack('c', raw_data[0:1])[0]
    L = struct.unpack('c', raw_data[1:2])[0]
    O1 = struct.unpack('c', raw_data[2:3])[0]
    O2 = struct.unpack('c', raw_data[3:4])[0]
    pkt_type = struct.unpack('B', raw_data[5:6])[0]
    next_record = struct.unpack('H', raw_data[6:8])[0]
    except Exception:
    self.lastKnownError = "Invalid data format"
    return False

    if L != 'L' and O1 != 'O' and O2 != 'O':
    self.lastKnownError = "Unknown packet encoding"
    return False

    pressure = struct.unpack('H', raw_data[8:10])[0] / 1000
    pressure *= 3.386 # inHg to kPa
    log.info("Barometer: %s" % pressure)
    self.addValue(RMParser.dataType.PRESSURE, timestamp, pressure)

    outside_temp = struct.unpack('h', raw_data[13:15])[0] / 10
    outside_temp = convertFahrenheitToCelsius(outside_temp)
    log.info("Outside Temp: %s" % outside_temp)
    self.addValue(RMParser.dataType.TEMPERATURE, timestamp, outside_temp)

    #wind_speed = struct.unpack('B', raw_data[15:16])[0]
    #wind_dir = struct.unpack('H', raw_data[17:19])[0]
    ten_min_avg_wind_spd = struct.unpack('B', raw_data[16:17])[0]
    ten_min_avg_wind_spd /= 2.237 # mph to mps
    log.info("Wind Speed (10min avg): %s" % ten_min_avg_wind_spd)

    out_hum = struct.unpack('B', raw_data[34:35])[0]
    log.info("Humidity: %s" % out_hum)
    self.addValue(RMParser.dataType.RH, timestamp, out_hum)

    #rain_rate = struct.unpack('H', raw_data[42:44])[0] * 0.01
    if self.params["useSolarRadiation"]:
    solar_radiation = struct.unpack('H', raw_data[45:47])[0]
    log.info("Solar Radiation: %s" % solar_radiation)
    self.addValue(RMParser.dataType.SOLARRADIATION, timestamp, solar_radiation)

    day_rain = struct.unpack('H', raw_data[51:53])[0] * 0.01
    day_rain = convertInchesToMM(day_rain)
    log.info("Day Rain: %s", day_rain)
    self.addValue(RMParser.dataType.RAIN, timestamp, day_rain)

    if self.params["useStationEvapoTranpiration"]:
    day_et = struct.unpack('H', raw_data[57:59])[0] / 1000
    day_et = convertInchesToMM(day_et)
    log.info("Day EvapoTranspiration: %s" % day_et)

    #xmtr_battery_status = struct.unpack('?', raw_data[87:88])[0]
    #console_battery_volts = ((struct.unpack('h', raw_data[88:90])[0] * 300) / 512) / 100.0

    forecast_icon = struct.unpack('c', raw_data[90:91])[0]
    rainmachine_icon = self.conditionConvert(ord(forecast_icon))
    log.info("Condition: %s -> %s" % (ord(forecast_icon), rainmachine_icon))
    self.addValue(RMParser.dataType.CONDITION, timestamp, rainmachine_icon)
    #crc = struct.unpack('h', raw_data[98:100])[0]

    return True


    def conditionConvert(self, forecast_icons):
    if forecast_icons == 2:
    return RMParser.conditionType.MostlyCloudy
    elif forecast_icons == 3 or forecast_icons == 7:
    return RMParser.conditionType.LightRain
    elif forecast_icons == 8:
    return RMParser.conditionType.Fair
    elif forecast_icons == 6:
    return RMParser.conditionType.PartlyCloudy
    elif forecast_icons == 18:
    return RMParser.conditionType.Snow
    elif forecast_icons == 19:
    return RMParser.conditionType.RainSnow
    else:
    return RMParser.conditionType.Unknown


    def getParamAsString(self, param):
    try:
    param = param.strip()
    except Exception:
    return None

    if not param:
    return None

    return param

    if __name__ == "__main__":
    parser = WeatherLinkIP()
    parser.perform()
    0
    Comment actions Permalink
  • Avatar
    Noopara

    The parser has this statement: parserEnabled = True

    Does that mean that it should load automatically when RM is powered up?  Is the parser saved in non-volatile memory when it is uploaded?  If so, it seems that it should load.

    What might be the problem?

     

    0
    Comment actions Permalink
  • Avatar
    RainMachine Nicholas

    It should be autoloading at the reboot. Could you try to DELETE it from Web UI and upload it again, enable, save and run it ? I will do the same steps on my machine and get back to you.

    0
    Comment actions Permalink
  • Avatar
    Noopara (Edited )

    I just tried it and it still doesn't load it.  There's nothing in the log regarding the weatherlinkip parser.

    What I did is delete the parser, load it, save it and then reboot the device.

     

    0
    Comment actions Permalink
  • Avatar
    Noopara

    Nicholas,

    Anything new on this problem?  The parser still won't load on boot up.

     

    0
    Comment actions Permalink
  • Avatar
    RainMachine Nicholas

    Not yet, I will update this message once I have more information.

    0
    Comment actions Permalink
  • Avatar
    RainMachine Nicholas

    Please check my reply in the Issues forum: https://support.rainmachine.com/hc/en-us/community/posts/360027368853-weatherlinkip-parser-not-loading-at-startup

    0
    Comment actions Permalink

Please sign in to leave a comment.