Skip to content

Commit

Permalink
Add Ambient Weather Data Source Support
Browse files Browse the repository at this point in the history
  • Loading branch information
leoherzog authored Jun 23, 2023
1 parent 4571bc7 commit a2cdaaf
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 28 deletions.
59 changes: 34 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -62,6 +63,14 @@ and periodically sends it on to
- Set your `weatherflowPUT` on line 24
- Set your `weatherflowSationId` on Line 25
</details>
<details>
<summary>Ambient Weather</summary>
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
</details>

- and choose one or more your forwarding destinations:

Expand All @@ -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
</details>
<details>
<summary>Windy</summary>

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.
</details>
<details>
<summary>PWSWeather</summary>

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
</details>
<details>
<summary>WeatherCloud</summary>
Expand All @@ -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
</details>
<details>
<summary>OpenWeatherMap</summary>

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
</details>
<details>
<summary>WindGuru</summary>
Expand All @@ -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
</details>
<details>
<summary>NOAA Citizen Weather Observer Program (CWOP)</summary>

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
</details>

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.
Expand All @@ -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
Expand Down
71 changes: 68 additions & 3 deletions code.gs
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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

Expand Down Expand Up @@ -55,6 +58,8 @@ const updateCWOP = false;
const cwopStationIDOrHamCallsign = 'CW0001';
const cwopValidationCode = null;



/*
____ _ _ _ _____ _ _ _ ____ _
| _ \ ___ | \ | | ___ | |_ | ____|__| (_) |_ | __ ) ___| | _____ __
Expand All @@ -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));
Expand All @@ -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();
Expand Down Expand Up @@ -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);

}

/*
____ _
/ ___| ___ _ __ __| | ___ _ __ ___
Expand Down Expand Up @@ -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); }

0 comments on commit a2cdaaf

Please sign in to comment.