Uploading data to Weatherunderground

I found this example on a old post

It is a closed topic.

I am trying to implement it in OH3 but i have no option in the scripting to use python?

Does anyone have a script that works in OH3 for uploading data to WU, i have a station and api key.

That script isn’t an OH rule. It’s a Python script that is completely separate from and independent from openHAB. Install Python and the Rules DSL rule shown there will call that script as an external program.

I am aware its a python file, but my OH3 installation does not have anyway to work with python, how do i install python scripting in OH3. There is no drop down for python in scripting. Or do i just drop the python file into one of the openhab directories, in which case what directory.

You miss my point. That Python script doesn’t run in openHAB. It runs completely independently from openHAB. You will not find anything anywhere in the OH UI or configurations that mention anything about Python because this script isn’t run inside of openHAB.

The only thing openHAB has to do with that Python script is this one line from the rule.

executeCommandLine("python3", "/etc/openhab/scripts/weatherundeground.py")

This is the equivalent to you ssh’ing to the machine and typing python3 /etc/openhab/scripts/weatherundergroud.py.

You need to install Python3 on your operating system and verify that you can execute the script from the command line separately and independently from openHAB. And then openHAB will be able to run the Python script too, just like you do from the command line.

Except for the fact that you found this Python script on an openHAB forum and it uses HTTP to get some data from openHAB’s REST API, this python script has nothing to do with openHAB. It’s its own separate program.

Or… you can do it all from rules DSL directly. See an example rule in the readme of the meteostick binding:
Meteostick binding OH3.4

yes i am aware, i did fix the original problem of not being able to work with python scripts in oh3. I needed to install the add on to get the option to make a python scripts. Unfoturnatly the script no longer works, there are many errors in the section that uses the rest api to get the values.

Thanks for the link, i think it will give me enought to get it working without using python.

No, you still are not aware. That script is not an openHAB rule. It does not and never will run inside of openHAB even if you install the Jython add-on. It’s not an openHAB script.

You could run the Python script on a completely different machine from the one that openHAB is running on. The script is not a part of OH, does not run inside of OH, and there is nothing you can add to openHAB or do to openHAB that will change that. All you can do is invoke the script from an OH rule using executeCommandLine or using the Exec binding.

The reason there were errors are:

  • the script is not an OH rule
  • the script is written in Python 3 but the Jython add-on only provides Python 2.7

One caution regarding the following line:

'humidity' ->         DavisVantageVueHumidity.state,

This supposes that the humidity item is an actual dimensionless number. The upload api for wunderground (or actually weather.com) requires that no dimension (or unit) is sent and your sent value is a percentage. So you send 68 for humidity, which is assumed to be % by weather.com.

In OH4 I’ve added the unit “%” to my humidity and the above rule will send “68 %” to weather.com, which fails as a valid numer and no humidity will be displayed on weather underground. In that case convert the state to a dimensionless value like

DavisVantageVueHumidity.getStateAs(QuantityType).intValue

Or doublevalue, whatever suits your dimensionless/unitless need.

I am aware, what i was talking about was the ability to EDIT the script within openhab which requires the addon. The script does not work because it is not using the rest api properly which is all likely syntax between the two versions of python. I have abandoned it anyway to use the solution on another response which uses the DSL directly. So to be clear, if you want to edit a python script or create the file within openhab, you need to install the addon, and likely the helper files as well.

Yes for sure, i have all my data without units in oh4. I was already sending data to WU via a raspberry Pi4 but I am converting to send directly from the OH server since i have access to a lot more sensors via it, i don’t use the davis unit did have one years ago but they are so pricey now, my data is all sensors on esp32 boards now. I also believe as another caveat, WU requires one to send the DewPoint reading as well or it won’t take the upload, but that is an easy calculation i can do when the script runs. I am confident with a little time i can get the rule working without the davis unit.

But OH only really lets you edit managed OH rules in the UI. Managed rules get saved to the JSONDB, not as separate files, meaning this Python script which is not actually an OH rule could never be run because it’s not a .py file on the file system somewhere.

If it’s a separate .py file under $OH_CONF/automation/jython (or some such, I don’t remember exactly) you can’t actually edit the Python script in MainUI, you can only view it, because it’s not a managed rule. And since this script isn’t an OH rule in the first place you wouldn’t even be able to view it because it won’t be recognized as a rule so won’t show it.

I want to make it absolutely clear to all future readers of this thread that you cannot simply install an add-on and have the ability to write and edit generic Python scripts that can be executed by an external Python interpreter. You can only enable the ability to write managed OH rules in the language the add-on provides in the UI or unmanaged rules which must conform to a certain format in separate files under $OH_CONF/automation that cannot be edited in the UI at all.

A generic Python script will not work as an OH rule because it lacks all the extra code necessary to create and register itself as a rule in OH. That’s where the helper libraries come in as they make it easier to create rules, but and generic Python script would need to be rewritten using these libraries. There mere presence does not suddenly make generic Python scripts look like and work like an OH rule.

Finally, the original script is Python 3 and there is currently no support for Python 3 using any add-on in OH. The Jython add-on provides Python 2.7 and Python 3 is not backwards compatible.

After you install the addon, you can actually create, edit, and save a python file. When i posted the thread i did not have the python option in the create script screen. I has it now.

I created the script and pasted the python code into the blank screen and saved it, i did not have to do any of that outside the UI. It’s the WU_UPDATE script in the pictures below. The other one is the DSL version of the new script I am testing.

The second picture show the Python option in the add script screen that was added as an option by the addon.

The script was invoked as it should have been, but had syntax errors due to the python version.

Untitled picture

No, that creates, edits, and manages an openHAB Rule that includes a Script Action written in Python. See Rules | openHAB. In this context, a “Script” is a

  • A UI rule consisting only of a single Script Action with the tag “Script”.
  • These will appear in a specific “Scripts” section on MainUI.

It is not a generic Python script. The code posted there must conform to the requirements of an OH rule. There is no .py file created anywhere. Unless you’ve gone through the painful process of installing the required third party libraries (i.e. requests and pytemperature in a way that OH can see and understand those are unavailable as well.

You cannot just paste some random stand alone Python script (nor JavaScript nor Ruby nor Groovy) into an OH rule (including “Scripts” in MainUI) and expect it to work, even if it were the correct version of Python. You encountered syntax errors because of the Python version first because a 2.7 interpreter doesn’t even know how to load 3.x Python code. But even if the code were written for Python 2.7 it wouldn’t have worked because the code is not written as an OH rule. The external libraries (requests and pytemperature) it uses are not installed.

“Scripts” in MainUI isn’t just a way to write random shell scripts that run on the machine where OH is running. These are a specific type of OH rule and have the same requirements that all OH rules have and run in the same environment that all OH rules run in.

And frankly, there would be no need to use the REST API like that Python script does if this were written as an OH Rule. The states of the Items could be retrieved directly without the HTTP calls and parsing the JSON returned.

I wrote the example for the Meteostick binding that uploads weather station observations to WU. You can see it here. I’ve used it or one nearly identical to it for years now. (Too bad my appearance in the commit history of this binding disappeared, but I can’t say I’m surprised.)

2 Likes

Unfortunately I can not really get it working anymore, most of the commands don’t work in OH4.

I originally had a raspberryPi4b running software called SkyWeather with some special hardware, i have been trying to port what it is doing to send data to WU since i know it works.

It is written originally in Python, and i can’t get anything python to work in openhab.

I tried a rule with and inline script but it doesn’t work either, lol.

Here is my rule

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: WU_Temperature
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-2
         val id = 'xxxxxxxxx';
         val pw = 'xxxxxxxxx';
         val double rh = WU_Humidity.getStateAs(DecimalType).doubleValue
         val double tempc = ((WU_Temperature.getStateAs(DecimalType).doubleValue - 32) * 5) / 9
         val double dewptc = 243.04 * (Math.log(rh/100) + ((17.625 * tempc) / (243.04 + tempc))) / (17.625 - Math.log(rh/100) - ((17.625 * tempc) / (243.04 + tempc)))
         val double dewptf = new QuantityType(dewptc, CELSIUS).toUnit('°F').doubleValue
         val double BaroInHG = WU_Pressure * 0.02952998751 //convert to inHG
           
         // https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=KCASANFR5&PASSWORD=XXXXXX&dateutc=2000-01-01+10%3A32%3A35&winddir=230&windspeedmph=12&windgustmph=12&tempf=70&rainin=0&baromin=29.1&dewptf=68.2&humidity=90&weather=&clouds=&softwaretype=vws%20versionxx&action=updateraw

         // build the URL
         myURL = "ID=" + id
         myURL += "&PASSWORD=" + pw 
         myURL += "&dateutc=now"

         // now weather station variables
         myURL += "&winddir=%i" % currentWindDirection
         myURL += "&windspeedmph=%0.2f" % (currentWindSpeed/1.6)
         myURL += "&windgustmph=%0.2f" % (currentWindGust/1.6)
         myURL += "&humidity=%i" % rh
         myURL += "&tempf=%0.2f" % WU_Temperature.getStateAs(DecimalType).doubleValue
         myURL += "&dewptf=%0.2f" % dewptf
         myURL += "&rainin=%0.2f" % WU_RainfallHour.getStateAs(DecimalType).doubleValue
         myURL += "&dailyrainin=%0.2f" % WU_RainfallDay.getStateAs(DecimalType).doubleValue
         myURL += "&baromin=%0.2f" % BaroInHG
         myURL += "&indoortempf=%0.2f" % ((HTUtemperature*9.0/5.0)+32.0)
         myURL += "&uv=%0.2f" % (SunlightUVIndex)
         myURL += "&indoorhumidity%0.2f=" % HTUhumidity
         //myURL += "&UV%0.2f=" % SunlightUVIndex
         myURL += "&software=OpenHab"   
             
         #send it
         //r = requests.get("https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php", params=myURL)  

         logDebug('PWS', 'url is {}', myURL)
         sendHttpGetRequest("https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php", myURL)
    type: script.ScriptAction

Here is the output in the openhab.log when it is run

2024-06-21 23:02:10.983 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'PWS' failed:  var myURL;
 val id = 'xxxxxxxx';
 val pw = 'xxxxxxx';
 val double rh = WU_Humidity.getStateAs(DecimalType).doubleValue
 val double tempc = ((WU_Temperature.getStateAs(DecimalType).doubleValue - 32) * 5) / 9
 val double dewptc = 243.04 * (Math.log(rh/100) + ((17.625 * tempc) / (243.04 + tempc))) / (17.625 - Math.log(rh/100) - ((17.625 * tempc) / (243.04 + tempc)))
 val double dewptf = new QuantityType(dewptc, CELSIUS).toUnit('°F').doubleValue
 val double BaroInHG = WU_Pressure * 0.02952998751 //convert to inHG
   
 // https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=KCASANFR5&PASSWORD=XXXXXX&dateutc=2000-01-01+10%3A32%3A35&winddir=230&windspeedmph=12&windgustmph=12&tempf=70&rainin=0&baromin=29.1&dewptf=68.2&humidity=90&weather=&clouds=&softwaretype=vws%20versionxx&action=updateraw

 // build the URL
 myURL = "ID=" + id
 myURL += "&PASSWORD=" + pw 
 myURL += "&dateutc=now"

 // now weather station variables
 myURL += "&winddir=%i" % currentWindDirection
 myURL += "&windspeedmph=%0.2f" % (currentWindSpeed/1.6)
 myURL += "&windgustmph=%0.2f" % (currentWindGust/1.6)
 myURL += "&humidity=%i" % rh
 myURL += "&tempf=%0.2f" % WU_Temperature.getStateAs(DecimalType).doubleValue
 myURL += "&dewptf=%0.2f" % dewptf
 myURL += "&rainin=%0.2f" % WU_RainfallHour.getStateAs(DecimalType).doubleValue
 myURL += "&dailyrainin=%0.2f" % WU_RainfallDay.getStateAs(DecimalType).doubleValue
 myURL += "&baromin=%0.2f" % BaroInHG
 myURL += "&indoortempf=%0.2f" % ((HTUtemperature*9.0/5.0)+32.0)
 myURL += "&uv=%0.2f" % (SunlightUVIndex)
 myURL += "&indoorhumidity%0.2f=" % HTUhumidity
 //myURL += "&UV%0.2f=" % SunlightUVIndex
 myURL += "&software=OpenHab"   
     
 #send it
 //r = requests.get("https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php", params=myURL)  

 logDebug('PWS', 'url is {}', myURL)
 sendHttpGetRequest("https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php", myURL)

Here is the original working pythons script that actually sent the data once a call to the subroutine was made.

#
# Send SkyWeather Information to the WeatherUnderground
#
# SwitchDoc Labs September, 2016
# modifications November 2016 - Luksmann - changed to request library to improve reliablity
#
import sys
import requests
# import httplib
import http.client as httplib

try:
    import conflocal as config
except ImportError:
    import config

def sendWeatherUndergroundData( stationid, stationkey, as3935LightningCount, as3935, as3935LastInterrupt, as3935LastDistance, as3935LastStatus, currentWindSpeed, currentWindGust, totalRain, bmp180Temperature, bmp180Pressure, bmp180Altitude,  bmp180SeaLevel, outsideTemperature, outsideHumidity, crc_check, currentWindDirection, currentWindDirectionVoltage, HTUtemperature, HTUhumidity, rain60Minutes, SunlightUVIndex):

    # https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=KCASANFR5&PASSWORD=XXXXXX&dateutc=2000-01-01+10%3A32%3A35&winddir=230&windspeedmph=12&windgustmph=12&tempf=70&rainin=0&baromin=29.1&dewptf=68.2&humidity=90&weather=&clouds=&softwaretype=vws%20versionxx&action=updateraw

    # build the URL
    #myURL = "ID="+config.WeatherUnderground_StationID
    #myURL += "&PASSWORD="+config.WeatherUnderground_StationKey
    myURL = "ID=" + stationid
    myURL += "&PASSWORD=" + stationkey 
    myURL += "&dateutc=now"

    # now weather station variables

    myURL += "&winddir=%i" % currentWindDirection
    # print ("cws=|",currentWindSpeed)

    myURL += "&windspeedmph=%0.2f" % (currentWindSpeed/1.6)
    myURL += "&windgustmph=%0.2f" % (currentWindGust/1.6)

    myURL += "&humidity=%i" % outsideHumidity
    myURL += "&tempf=%0.2f" % (32.0+1.8*outsideTemperature)

    dewpoint =  outsideTemperature - ((100.0 - outsideHumidity) / 5.0);
    dewpointf = ((dewpoint*9.0/5.0)+32.0)
    myURL += "&dewptf=%0.2f" % dewpointf

    myURL += "&rainin=%0.2f" % ((rain60Minutes)/25.4)
    myURL += "&dailyrainin=%0.2f" % ((totalRain)/25.4)
    myURL += "&baromin=%0.2f" % (((bmp180SeaLevel) * 0.2953)/10.0)

    myURL += "&indoortempf=%0.2f" % ((HTUtemperature*9.0/5.0)+32.0)
    myURL += "&uv=%0.2f" % (SunlightUVIndex)
    myURL += "&indoorhumidity%0.2f=" % HTUhumidity
    # myURL += "&UV%0.2f=" % SunlightUVIndex
    myURL += "&software=SkyWeather"


    if (config.WU_debug == True):
        print ("myURL=", myURL)
    #send it
    r = requests.get("https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php", params=myURL)
    if (config.WU_debug == True):
        print(r.url)
    print(r.text)

I suppose making a URL and adding data to the parameters and sending a get request should be a simple task but I am in way over my head i suppose, been hours fiddling to no avail. I did x out the site id and the password in the code sections.

Script execution of rule with UID 'PWS' failed:  var myURL;

Looking at your script you just start the variable “myURL” without declaring it as a variable. So the first time you use “myURL” you have to say it is a variable:

         // build the URL
         var myURL = "ID=" + id
         myURL += "&PASSWORD=" + pw

Have a good look at the rule linked by John Cocula in the post above you and use that to work on your own script.

1 Like

To amplify what @Chiuaua79 said, but also to point out that the rule I wrote is in openHAB’s original DSL rules language, and ought to work if used as described at the link, and have it trigger off a weather observation item that changes every couple of minutes. I attach my current version which still works fine under OH 4.1.3, and also updates PWS Weather:

import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Map
import java.util.TimeZone

/* Uploads weather station data using this format:

   http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol
 */

rule PWS
when
	Item DavisVantageVueWindDirectionAverage received update
then
	val id = 'XXXXX'
	val pw = 'xxxxx'
	val sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss')
	sdf.setTimeZone(TimeZone.getTimeZone('UTC'))
	val double rh = DavisVantageVueHumidity.getStateAs(DecimalType).doubleValue
	val double tempc = DavisVantageVueOutdoorTemperature.getStateAs(QuantityType).toUnit('°C').doubleValue
	val double dewptc = 243.04 * (Math.log(rh/100) + ((17.625 * tempc) / (243.04 + tempc))) / (17.625 - Math.log(rh/100) - ((17.625 * tempc) / (243.04 + tempc)))
	val double dewptf = new QuantityType(dewptc, CELSIUS).toUnit('°F').doubleValue
	val Map<String, Object> params = newLinkedHashMap(
		'action' ->           'updateraw',
		'ID' ->               id,
		'PASSWORD' ->         pw,
		'dateutc' ->          sdf.format(new Date()),
		'winddir' ->          DavisVantageVueWindDirection.getStateAs(QuantityType).toUnit('°').intValue,
		'windspeedmph' ->     DavisVantageVueWindSpeed.getStateAs(QuantityType).toUnit('mph').doubleValue,
		'windgustmph' ->      DavisVantageVueWindSpeedMaximum.getStateAs(QuantityType).toUnit('mph').doubleValue,
		'windgustdir' ->      DavisVantageVueWindDirectionAverage.getStateAs(QuantityType).toUnit('°').intValue,
		'windspdmph_avg2m' -> DavisVantageVueWindSpeedAverage.getStateAs(QuantityType).toUnit('mph').doubleValue,
		'winddir_avg2m' ->    DavisVantageVueWindDirectionAverage.getStateAs(QuantityType).toUnit('°').intValue,
		'humidity' ->         DavisVantageVueHumidity.state,
		'dewptf' ->           dewptf,
		'tempf' ->            DavisVantageVueOutdoorTemperature.getStateAs(QuantityType).toUnit('°F').doubleValue,
		'rainin' ->           DavisVantageVueRainCurrentHour.getStateAs(QuantityType).toUnit('in').doubleValue,
		'baromin' ->          MeteoStickPressure.getStateAs(QuantityType).toUnit('inHg').doubleValue,
		'softwaretype' ->     'openHAB 2.4')

	var paramString = ''
	var first = true
	for (key : params.keySet()) {
		if (!first) {
			paramString += '&'
		}
		paramString += key + '=' + URLEncoder::encode(params.get(key).toString, 'UTF-8')
		first = false
	}

	var url = 'https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?' + paramString
	logDebug('PWS', 'url is {}', url)
	sendHttpGetRequest(url)

	var url2 = 'https://www.pwsweather.com/pwsupdate/pwsupdate.php?' + paramString
	logDebug('PWS', 'url is {}', url2)
	sendHttpGetRequest(url2)
end

What java version are you using, my system is on Java 17 and i beleive all the imports throw errors because of it, as most of them are depricated.

My OH 4.1.3 is using Java 17 as it’s a requirement to do so. I never see any errors or warnings reported for this code and it runs approximately every two minutes.