Skip to content

Commit

Permalink
Merge pull request #3 from KvotheBloodless/FEATURE-1_rich_formatted_n…
Browse files Browse the repository at this point in the history
…otes

Missed files
  • Loading branch information
KvotheBloodless authored Dec 18, 2024
2 parents d3da8e2 + 0fc4ed6 commit f685801
Show file tree
Hide file tree
Showing 5 changed files with 349 additions and 0 deletions.
89 changes: 89 additions & 0 deletions plugin/activecaptain_client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* MIT License
*
* Copyright (c) 2024 Paul Willems <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

const axios = require('axios')

const baseUrl = 'https://activecaptain.garmin.com'
const userAgent = 'Signal K Active Captain Plugin'

axios.interceptors.request.use(request => {
// console.log('Starting Request', JSON.stringify(request, null, 2))
return request
}, error => {
Promise.reject(error)
})

axios.interceptors.response.use(response => {
// console.log('Received Response', JSON.stringify(response.data, null, 2))
return response
}, error => {
Promise.reject(error)
})

module.exports = {
listPointsOfInterest: function (app, x1, y1, x2, y2) {
const url = `${baseUrl}/community/api/v1/points-of-interest/bbox`

return axios.post(url, {
north: y1,
west: x1,
south: y2,
east: x2,
zoomLevel: 17
}, {
headers: {
'User-Agent': userAgent,
Accept: 'application/json'
}
}).then(response => {
return response.data.pointsOfInterest.map(p => {
return {
id: p.id,
type: p.poiType,
position: {
longitude: p.mapLocation.longitude,
latitude: p.mapLocation.latitude
},
name: p.name
}
})
}).catch(error => {
app.debug(`ERROR fetching points of interest list ${x1}, ${y1}, ${x2}, ${y2} - ${error}`)
})
},
pointOfInterestDetails: function (app, id) {
const url = `${baseUrl}/community/api/v1/points-of-interest/${id}/summary`

return axios.get(url, {
headers: {
'User-Agent': userAgent,
Accept: 'application/json'
}
}).then(response => {
return response.data
}).catch(error => {
app.debug(`ERROR fetching point of interest ${id} - ${error}`)
})
}
}
170 changes: 170 additions & 0 deletions plugin/handlebars_utilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/**
* MIT License
*
* Copyright (c) 2024 Paul Willems <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

const handlebars = require('handlebars')
const helpersForHandlebars = require('helpers-for-handlebars')
const fs = require('node:fs')
const moment = require('moment')

const EMPTY = ''
const UNKNOWN = 'Unknown'

const partialsDir = './node_modules/signalk-activecaptain-resources/plugin/partials/'

handlebars.registerPartial('header', fs.readFileSync(`${partialsDir}/header.hbsp`, 'utf-8'))
handlebars.registerPartial('business', fs.readFileSync(`${partialsDir}/business.hbsp`, 'utf-8'))
handlebars.registerPartial('dockage', fs.readFileSync(`${partialsDir}/dockage.hbsp`, 'utf-8'))
handlebars.registerPartial('fuel', fs.readFileSync(`${partialsDir}/fuel.hbsp`, 'utf-8'))
handlebars.registerPartial('amenities', fs.readFileSync(`${partialsDir}/amenities.hbsp`, 'utf-8'))
handlebars.registerPartial('contact', fs.readFileSync(`${partialsDir}/contact.hbsp`, 'utf-8'))
handlebars.registerPartial('review', fs.readFileSync(`${partialsDir}/review.hbsp`, 'utf-8'))

const templatesDir = './node_modules/signalk-activecaptain-resources/plugin/templates/'

const pointOfInterestTemplate = handlebars.compile(fs.readFileSync(`${templatesDir}/point_of_interest.hbs`, 'utf-8'))

module.exports = {
helpers: function () {
helpersForHandlebars.comparison()
helpersForHandlebars.array()

handlebars.registerHelper('fromNow', function (context, _) {
return moment(new Date(context)).fromNow()
})

handlebars.registerHelper('hasFuel', function (options) {
if (this.data.fuel) {
if (this.data.fuel.diesel !== UNKNOWN ||
this.data.fuel.ethanolFree !== UNKNOWN ||
this.data.fuel.gas !== UNKNOWN ||
this.data.fuel.propane !== UNKNOWN ||
this.data.fuel.electric !== UNKNOWN ||
this.data.fuel.notes.length > 0) {
return options.fn(this)
}
}
return options.inverse(this)
})

handlebars.registerHelper('hasDockage', function (options) {
if (this.data.dockage) {
if (this.data.dockage.liveaboard !== UNKNOWN ||
this.data.dockage.secureAccess !== UNKNOWN ||
this.data.dockage.securityPatrol !== UNKNOWN ||
this.data.dockage.notes.length > 0) {
return options.fn(this)
}
}
return options.inverse(this)
})

handlebars.registerHelper('hasContact', function (options) {
if (this.data.contact) {
if (this.data.contact.vhfChannel !== EMPTY ||
this.data.contact.phone !== EMPTY ||
this.data.contact.afterHourContact !== EMPTY ||
this.data.contact.email !== EMPTY ||
this.data.contact.website !== EMPTY) {
return options.fn(this)
}
}
return options.inverse(this)
})

handlebars.registerHelper('hasAmenities', function (options) {
if (this.data.amenity) {
if (this.data.amenity.bar !== UNKNOWN ||
this.data.amenity.boatRamp !== UNKNOWN ||
this.data.amenity.cellReception !== UNKNOWN ||
this.data.amenity.courtesyCar !== UNKNOWN ||
this.data.amenity.laundry !== UNKNOWN ||
this.data.amenity.lodging !== UNKNOWN ||
this.data.amenity.pets !== UNKNOWN ||
this.data.amenity.restaurant !== UNKNOWN ||
this.data.amenity.restroom !== UNKNOWN ||
this.data.amenity.shower !== UNKNOWN ||
this.data.amenity.transportation !== UNKNOWN ||
this.data.amenity.trash !== UNKNOWN ||
this.data.amenity.water !== UNKNOWN ||
this.data.amenity.wifi !== UNKNOWN) {
return options.fn(this)
}
}
return options.inverse(this)
})

handlebars.registerHelper('hasBusiness', function (options) {
if (this.data.business) {
if (this.data.business.cash !== UNKNOWN ||
this.data.business.check !== UNKNOWN ||
this.data.business.credit !== UNKNOWN ||
this.data.business.public !== UNKNOWN ||
this.data.business.seasonal !== UNKNOWN ||
this.data.business.notes.length > 0) {
return options.fn(this)
}
}
return options.inverse(this)
})
},
anchorage: function (data) {
return pointOfInterestTemplate({ data })
},
hazard: function (data) {
return pointOfInterestTemplate({ data })
},
marina: function (data) {
return pointOfInterestTemplate({ data })
},
localKnowledge: function (data) {
return pointOfInterestTemplate({ data })
},
navigational: function (data) {
return pointOfInterestTemplate({ data })
},
boatRamp: function (data) {
return pointOfInterestTemplate({ data })
},
business: function (data) {
return pointOfInterestTemplate({ data })
},
inlet: function (data) {
return pointOfInterestTemplate({ data })
},
lock: function (data) {
return pointOfInterestTemplate({ data })
},
dam: function (data) {
return pointOfInterestTemplate({ data })
},
ferry: function (data) {
return pointOfInterestTemplate({ data })
},
airport: function (data) {
return pointOfInterestTemplate({ data })
},
bridge: function (data) {
return pointOfInterestTemplate({ data })
}
}
25 changes: 25 additions & 0 deletions plugin/partials/amenities.hbsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<hr/>
<div>
<h4>🏨 Amenities</h4>
{{#if bar}}{{#if (eq bar "Yes")}}✅{{else}}❌{{/if}} Bar<br/>{{/if}}
{{#if cellReception}}{{#if (eq cellReception "Yes")}}✅{{else}}❌{{/if}} Cell reception<br/>{{/if}}
{{#if boatRamp}}{{#if (eq boatRamp "Yes")}}✅{{else}}❌{{/if}} Boat ramp<br/>{{/if}}
{{#if laundry}}{{#if (eq laundry "Yes")}}✅{{else}}❌{{/if}} Laundry<br/>{{/if}}
{{#if courtesyCar}}{{#if (eq courtesyCar "Yes")}}✅{{else}}❌{{/if}} Courtesy car<br/>{{/if}}
{{#if pets}}{{#if (eq pets "Yes")}}✅{{else}}❌{{/if}} Pets allowed<br/>{{/if}}
{{#if lodging}}{{#if (eq lodging "Yes")}}✅{{else}}❌{{/if}} Lodging<br/>{{/if}}
{{#if restroom}}{{#if (eq restroom "Yes")}}✅{{else}}❌{{/if}} Restrooms<br/>{{/if}}
{{#if restaurant}}{{#if (eq restaurant "Yes")}}✅{{else}}❌{{/if}} Restaurant<br/>{{/if}}
{{#if transportation}}{{#if (eq transportation "Yes")}}✅{{else}}❌{{/if}} Transportation<br/>{{/if}}
{{#if shower}}{{#if (eq shower "Yes")}}✅{{else}}❌{{/if}} Showers<br/>{{/if}}
{{#if water}}{{#if (eq water "Yes")}}✅{{else}}❌{{/if}} Water<br/>{{/if}}
{{#if trash}}{{#if (eq trash "Yes")}}✅{{else}}❌{{/if}} Rubbish disposal<br/>{{/if}}
{{#if wifi}}{{#if (eq wifi "Yes")}}✅{{else}}❌{{/if}} Wifi<br/>{{/if}}
</div>
{{#if notes}}
<div>
{{#each notes}}
<p>{{this.field}}: {{this.value}}</p>
{{/each}}
</div>
{{/if}}
58 changes: 58 additions & 0 deletions plugin/position_utilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* MIT License
*
* Copyright (c) 2024 Paul Willems <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

module.exports = {
positionToBbox: function (position, distanceMeters) {
const nwCoords = calculateNewPosition(position[0], position[1], -45, distanceMeters / 1000)
const seCoords = calculateNewPosition(position[0], position[1], 135, distanceMeters / 1000)

return [nwCoords.longitude, nwCoords.latitude, seCoords.longitude, seCoords.latitude]
}
}

function calculateNewPosition (longitude, latitude, bearing, distanceKms) {
const earthRadius = 6371 // Radius of the Earth in kilometers
const latitudeRad = toRadians(latitude)
const longitudeRad = toRadians(longitude)
const bearingRad = toRadians(bearing)

const newLatitudeRad = Math.asin(Math.sin(latitudeRad) * Math.cos(distanceKms / earthRadius) +
Math.cos(latitudeRad) * Math.sin(distanceKms / earthRadius) * Math.cos(bearingRad))

const newLongitudeRad = longitudeRad + Math.atan2(Math.sin(bearingRad) * Math.sin(distanceKms / earthRadius) * Math.cos(latitudeRad),
Math.cos(distanceKms / earthRadius) - Math.sin(latitudeRad) * Math.sin(newLatitudeRad))

const newLatitude = toDegrees(newLatitudeRad)
const newLongitude = toDegrees(newLongitudeRad)

return { latitude: newLatitude, longitude: newLongitude }
}

function toRadians (degrees) {
return degrees * Math.PI / 180
}

function toDegrees (radians) {
return radians * 180 / Math.PI
}
7 changes: 7 additions & 0 deletions plugin/templates/point_of_interest.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{> header}}
{{#hasDockage}}{{> dockage data.dockage}}{{/hasDockage}}
{{#hasContact}}{{> contact data.contact}}{{/hasContact}}
{{#hasFuel}}{{> fuel data.fuel}}{{/hasFuel}}
{{#hasAmenities}}{{> amenities data.amenity}}{{/hasAmenities}}
{{#hasBusiness}}{{> business data.business}}{{/hasBusiness}}

0 comments on commit f685801

Please sign in to comment.