diff --git a/README.md b/README.md index 881e126..01e5652 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ This code is built to be hosted on the free [Google Apps Script](https://develop - [Wunderground](https://wunderground.com/member/api-keys), - [MyAcurite](https://myacurite.com/), -- [Davis WeatherLink](https://weatherlink.com/), or -- [WeatherFlow Tempest](https://tempestwx.com/) +- [Davis WeatherLink](https://weatherlink.com/), +- [WeatherFlow Tempest](https://tempestwx.com/), or +- [Ambient Weather](https://ambientweather.net/), and periodically sends it on to @@ -62,6 +63,14 @@ and periodically sends it on to - Set your `weatherflowPUT` on line 24 - Set your `weatherflowSationId` on Line 25 +
+ Ambient Weather + + Uses the [Ambient Weather](https://ambientweather.net/account) API. + - Set the `datasource` to `ambient` on Line 10 + - Set your `ambientWeatherStationName` on line 27 + - Set your `ambientWeatherApiKey` on Line 28 +
- and choose one or more your forwarding destinations: @@ -70,27 +79,27 @@ and periodically sends it on to To send to [Wunderground](https://support.weather.com/s/article/PWS-Upload-Protocol): - - Set `updateWunderground` to `true` on Line 29 - - Set your `wundergroundAPIKey` on Line 30 - - Set your `wundergroundStationId` on line 31 + - Set `updateWunderground` to `true` on Line 32 + - Set your `wundergroundAPIKey` on Line 33 + - Set your `wundergroundStationId` on line 34
Windy To send to [Windy.com](https://community.windy.com/topic/8168/report-your-weather-station-data-to-windy): - - Set `updateWindy` to `true` on Line 33 - - Set your `windyAPIKey` on Line 34 - - Set your `windyStationId` on line 35. It's likely `0`, `1`, `2`, etc. + - Set `updateWindy` to `true` on Line 36 + - Set your `windyAPIKey` on Line 37 + - Set your `windyStationId` on line 38. It's likely `0`, `1`, `2`, etc.
PWSWeather To send to [PWSWeather](https://dashboard.pwsweather.com/): - - Set `updatePWSWeather` to `true` on Line 37 - - Set your `pwsWeatherAPIKey` from your station's admin page on line 38 - - Set your `pwsWeatherStationID` on Line 39 + - Set `updatePWSWeather` to `true` on Line 40 + - Set your `pwsWeatherAPIKey` from your station's admin page on line 41 + - Set your `pwsWeatherStationID` on Line 42
WeatherCloud @@ -99,19 +108,19 @@ and periodically sends it on to Retrieve your station's ID and API Key by going to [your Devices](https://app.weathercloud.net/devices), then clicking Settings → 🔌 Link on your station. - - Set `updateWeatherCloud` to `true` on Line 41 - - Set your `weathercloudStationId` on line 42 - - Set your `weathercloudAPIKey` on Line 43 - - Set whether or not you have a WeatherCloud Pro or Premium account with `hasWeatherCloudPro` as `true` or `false` on line 44 + - Set `updateWeatherCloud` to `true` on Line 44 + - Set your `weathercloudStationId` on line 45 + - Set your `weathercloudAPIKey` on Line 46 + - Set whether or not you have a WeatherCloud Pro or Premium account with `hasWeatherCloudPro` as `true` or `false` on line 47
OpenWeatherMap Creation of a new OpenWeatherMap station must be done by API, not on the OpenWeatherMap website. More information is available in [the OpenWeatherMap Station API documentation](https://openweathermap.org/stations#create_station). The basic concept for what must be done is available in the `createNewOWMStation_()` function. Remove the `_` character from the name of that function to make it selectable from the `▷ Run` button in the toolbar. If you do so, make sure you note your new station's ID and other details in the log (available in the Executions tab in the sidebar after running!), then: - - Set `updateOpenWeatherMap` to `true` on Line 46 - - Set `openWeatherMapAPIKey` to your [API Key](https://home.openweathermap.org/api_keys) on Line 47 - - Set your `openWeatherMapStationId` to [your OpenWeatherMap station's `external_id`](https://openweathermap.org/stations#create_station) on line 48 + - Set `updateOpenWeatherMap` to `true` on Line 49 + - Set `openWeatherMapAPIKey` to your [API Key](https://home.openweathermap.org/api_keys) on Line 50 + - Set your `openWeatherMapStationId` to [your OpenWeatherMap station's `external_id`](https://openweathermap.org/stations#create_station) on line 51
WindGuru @@ -120,18 +129,18 @@ and periodically sends it on to Start by [registering a new "Other / Upload API" station](https://stations.windguru.cz/register.php?id_type=16), then: - - Set `updateWindGuru` to `true` on Line 50 - - Set `windGuruStationUID` to your chosen [station UID](https://stations.windguru.cz/) on Line 51 - - Set your `windGuruStationPassword` to your chosen [station API password](https://stations.windguru.cz/) (note, not your _account's_ password) on line 52 + - Set `updateWindGuru` to `true` on Line 53 + - Set `windGuruStationUID` to your chosen [station UID](https://stations.windguru.cz/) on Line 54 + - Set your `windGuruStationPassword` to your chosen [station API password](https://stations.windguru.cz/) (note, not your _account's_ password) on line 55
NOAA Citizen Weather Observer Program (CWOP) Send to [CWOP](https://madis.ncep.noaa.gov/madis_cwop.shtml). Start by [registering for a new station](https://madis.ncep.noaa.gov/madis_cwop.shtml), then when you receive your email: - - Set `updateCWOP` to `true` on Line 54 - - Set `cwopStationIDOrHamCallsign` to your assigned CWOP station ID that you received via email on Line 55 - - If you are using your ham radio callsign as your station ID and you have received a validation code from NOAA CWOP support, set `cwopValidationCode` to your validation code on Line 56 + - Set `updateCWOP` to `true` on Line 57 + - Set `cwopStationIDOrHamCallsign` to your assigned CWOP station ID that you received via email on Line 58 + - If you are using your ham radio callsign as your station ID and you have received a validation code from NOAA CWOP support, set `cwopValidationCode` to your validation code on Line 59
4. Run the "Schedule" function with the `▷ Run` button in the toolbar. You're done! You can see it periodically running in the `☰▶` Executions tab on the left sidebar. @@ -141,7 +150,7 @@ If you ever make changes to the API keys or enabled services, just run the **Sch ## How to Update 1. Overwrite the code from [`code.gs`](https://github.com/leoherzog/WundergroundStationForwarder/releases/latest/download/code.gs) from [the latest release](https://github.com/leoherzog/WundergroundStationForwarder/releases/latest) in this repository to your `Code.gs` file and `💾 Save`. -2. Make sure your API Keys and settings on lines 10 through 56 are correct. +2. Make sure your API Keys and settings on lines 10 through 59 are correct. 3. Run the "Schedule" function again with the `▷ Run` button in the toolbar. ## License diff --git a/code.gs b/code.gs index 8495050..2c8fd4f 100644 --- a/code.gs +++ b/code.gs @@ -7,7 +7,7 @@ // Getting data -const datasource = 'ibm'; // 'ibm' (wunderground), 'acurite' (myacurite), 'davis' (weatherlink), or 'weatherflow' (tempestwx) +const datasource = 'ibm'; // 'ibm' (wunderground), 'acurite' (myacurite), 'davis' (weatherlink), 'weatherflow' (tempestwx), or 'ambient' (ambient weather) const ibmAPIKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; const ibmStationId = 'KXXXXXXXXXX'; @@ -23,6 +23,9 @@ const davisStationName = 'xxxxxxxxxxxxxxxx'; // or const weatherflowPUT = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'; const weatherflowStationId = 'xxxxx'; +// or +const ambientWeatherStationName = 'xxxxxx'; +const ambientWeatherApiKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // Sending data @@ -55,6 +58,8 @@ const updateCWOP = false; const cwopStationIDOrHamCallsign = 'CW0001'; const cwopValidationCode = null; + + /* ____ _ _ _ _____ _ _ _ ____ _ | _ \ ___ | \ | | ___ | |_ | ____|__| (_) |_ | __ ) ___| | _____ __ @@ -64,7 +69,7 @@ const cwopValidationCode = null; */ -let version = 'v2.2.0'; +let version = 'v2.3.0'; function Schedule() { ScriptApp.getProjectTriggers().forEach(trigger => ScriptApp.deleteTrigger(trigger)); @@ -85,6 +90,10 @@ function Schedule() { refreshFromWeatherflow_(); ScriptApp.newTrigger('refreshFromWeatherflow_').timeBased().everyMinutes(1).create(); break; + case 'ambient': + refreshFromAmbientWeather_(); + ScriptApp.newTrigger('refreshFromAmbientWeather_').timeBased().everyMinutes(1).create(); + break; } if (updateWunderground) ScriptApp.newTrigger('updateWunderground_').timeBased().everyMinutes(1).create(); if (updateWindy) ScriptApp.newTrigger('updateWindy_').timeBased().everyMinutes(5).create(); @@ -426,6 +435,62 @@ function refreshFromWeatherflow_() { } +// https://ambientweather.docs.apiary.io/ +// https://github.com/ambient-weather/api-docs/wiki/Device-Data-Specs +function refreshFromAmbientWeather_() { + + let ambientWeatherDevices = fetchJSON_('https://rt.ambientweather.net/v1/devices?applicationKey=' + Utilities.newBlob(Utilities.base64Decode('NDNiYzQwMDgxOTc0NDVhNTk3NDg0ZjBiNjgwMjMxYTRiM2UwOTliNzc0NjY0MDlmYTgwN2Q3ZjQzN2YyYmViYg==')).getDataAsString() + '&apiKey=' + ambientWeatherApiKey); + if (!ambientWeatherDevices || !ambientWeatherDevices.length) return false; // still no luck? give up + // console.log(JSON.stringify(ambientWeatherDevices)); + + let station = ambientWeatherDevices.find(x => x.info.name === ambientWeatherStationName); + if (!station) throw 'Unable to find station named "' + ambientWeatherStationName + '" in your Ambient Weather account. Only ' + ambientWeatherDevices.map(x => x.info.name).join() + '.'; + + let conditions = {}; + conditions.time = station.lastData.dateutc; + conditions.latitude = station.info.coords.coords.lat; + conditions.longitude = station.info.coords.coords.lon; + if (station.lastData.tempf != null) conditions.temp = { + "f": Number(station.lastData.tempf), + "c": Number(station.lastData.tempf).fToC().toFixedNumber(1) + } + if (station.lastData.dewPoint != null) conditions.dewpoint = { + "f": Number(station.lastData.dewPoint), + "c": Number(station.lastData.dewPoint).fToC().toFixedNumber(1) + } + if (station.lastData.windspeedmph != null) conditions.windSpeed = { + "mph": Number(station.lastData.windspeedmph), + "mps": Number(station.lastData.windspeedmph).mphToMPS().toFixedNumber(1) + } + if (station.lastData.windgustmph != null) conditions.windGust = { + "mph": Number(station.lastData.windgustmph), + "mps": Number(station.lastData.windgustmph).mphToMPS().toFixedNumber(1) + } + if (station.lastData.winddir != null) conditions.winddir = station.lastData.winddir; + if (station.lastData.baromabsin != null) conditions.pressure = { + "inHg": Number(station.lastData.baromabsin), + "hPa": Number(station.lastData.baromabsin).inHgTohPa().toFixedNumber(1) + } + if (station.lastData.humidity != null) conditions.humidity = station.lastData.humidity; + if (station.lastData.uv != null) conditions.uv = station.lastData.uv; + if (station.lastData.solarradiation != null) conditions.solarRadiation = station.lastData.solarradiation; + if (station.lastData.hourlyrainin != null) conditions.precipRate = { + "in": Number(station.lastData.hourlyrainin), + "mm": Number(station.lastData.hourlyrainin).inTomm().toFixedNumber(2) + } + if (station.lastData['24hourrainin'] != null) conditions.precipTotal = { + "in": Number(station.lastData['24hourrainin']), + "mm": Number(station.lastData['24hourrainin']).inTomm().toFixedNumber(2) + } + + console.log(JSON.stringify(conditions)); + + // CacheService.getScriptCache().put('conditions', JSON.stringify(conditions), 21600); + + return JSON.stringify(conditions); + +} + /* ____ _ / ___| ___ _ __ __| | ___ _ __ ___ @@ -778,4 +843,4 @@ Number.prototype.inHgTohPa = function() { return this * 33.86389; } Number.prototype.hPaToinHg = function() { return this * 0.02953; } Number.prototype.inTomm = function() { return this * 25.4; } Number.prototype.mmToIn = function() { return this * 0.03937; } -Number.prototype.toFixedNumber = function(digits) { return +this.toFixed(digits); } +Number.prototype.toFixedNumber = function(digits) { return +this.toFixed(digits); } \ No newline at end of file