From feb2d2e86a9cd6b8f91c75d0eb29e0de7c7087e0 Mon Sep 17 00:00:00 2001 From: Hugo Holmqvist Date: Wed, 7 Oct 2020 21:24:52 +0300 Subject: [PATCH] Add temperature factor --- bagbeer-deploy/index.ts | 4 ++++ frontend/components/app.tsx | 24 +++++++++++++++++------- frontend/pages/index.tsx | 4 +++- service/src/app.ts | 22 +++++++++++++++++++--- service/src/resolvers/statusResolver.ts | 11 +++++++++-- service/src/service/agro.ts | 25 ++++++------------------- service/src/service/darksky.ts | 25 +++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 32 deletions(-) create mode 100644 service/src/service/darksky.ts diff --git a/bagbeer-deploy/index.ts b/bagbeer-deploy/index.ts index 97172a6..a455c28 100644 --- a/bagbeer-deploy/index.ts +++ b/bagbeer-deploy/index.ts @@ -38,6 +38,10 @@ const deployment = new k8s.apps.v1.Deployment('bagbeer-service', { { name: 'AGRO_API_TOKEN', valueFrom: getSecretRef('AGRO_API_TOKEN') + }, + { + name: 'DARKSKY_TOKEN', + valueFrom: getSecretRef('DARKSKY_TOKEN') } ] } diff --git a/frontend/components/app.tsx b/frontend/components/app.tsx index c38cbe2..4a88148 100644 --- a/frontend/components/app.tsx +++ b/frontend/components/app.tsx @@ -2,14 +2,15 @@ import React, { useState } from 'react' import additionalInfo from '../fixtures/statusAdditionalInfo' import format from 'date-fns/format' import { getCurrentStatus } from '../services/statusService' -import { useEffect } from 'react' type BagBeerStatusProps = { updated: Date, status: string, details: { groundMoisture: number, - windSpeed: number + windSpeed: number, + groundMoistureUpdated: Date, + temp: number } update: () => void } @@ -20,20 +21,26 @@ type Props = { status: string details: { groundMoisture: number, - windSpeed: number + windSpeed: number, + groundMoistureUpdated: Date, + temp: number } } | string } type DataContainerProps = { groundMoisture: number, - windSpeed: number + windSpeed: number, + groundMoistureUpdated: Date, + temp: number } const DataContainer = (props: DataContainerProps) =>
+

Ground moist. updated: {format(new Date(props.groundMoistureUpdated), 'd.M.yyyy kk:mm')}

Ground moisture: {props.groundMoisture}m3/m3

Wind speed: {props.windSpeed}m/s

+

Temperature: {props.temp}°C

const StatusContainer = (props: BagBeerStatusProps) => { @@ -44,7 +51,12 @@ const StatusContainer = (props: BagBeerStatusProps) => {

{additionalInfo[props.status]}

{dataContainerOpen && - } + }

{format(new Date(props.updated), 'd.M.yyyy kk:mm')}

@@ -76,6 +88,4 @@ const App = (props: Props) => { ) } - - export default App diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index e350632..a0d504c 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -9,7 +9,9 @@ export type InitialProps = { status: string, details: { groundMoisture: number, - windSpeed: number + windSpeed: number, + groundMoistureUpdated: Date, + temp: number } } | string } diff --git a/service/src/app.ts b/service/src/app.ts index 771dcc9..1bb65ab 100644 --- a/service/src/app.ts +++ b/service/src/app.ts @@ -1,8 +1,15 @@ import { Application } from 'https://deno.land/x/abc/mod.ts' import { logger } from 'https://deno.land/x/abc/middleware/logger.ts' -import { CORSConfig, cors } from 'https://deno.land/x/abc/middleware/cors.ts' +import { cors } from 'https://deno.land/x/abc/middleware/cors.ts' import maybe from 'https://raw.githubusercontent.com/MergHQ/denofun/maybe-get-or-else/lib/maybe.ts' -import { fetchCurrentStatus } from './service/agro.ts' +import { fetchCurrentData } from './service/agro.ts' +import { fetchCached } from './service/darksky.ts' +import resolveStatus from './resolvers/statusResolver.ts' + +if (!Deno.env.get('POLY_ID') || !Deno.env.get('AGRO_API_TOKEN') || !Deno.env.get('DARKSKY_TOKEN')) { + console.error('Missing env vars.') + Deno.exit(1) +} const app = new Application() @@ -10,7 +17,16 @@ app .use(logger()) .use(cors()) .get('/api/status', ctx => - fetchCurrentStatus() + Promise.all([fetchCurrentData(), fetchCached()]) + .then(([{ updated, details }, { temp, updated: tempUpdated }]) => ({ + updated: tempUpdated, + status: resolveStatus(details.groundMoisture, details.windSpeed, temp), + details: { + ...details, + temp, + groundMoistureUpdated: updated + } + })) .then(status => ctx.json(status)) .catch(e => ctx.json(e, e.status))) .get('/health', ctx => ctx.json({ ok: true })) diff --git a/service/src/resolvers/statusResolver.ts b/service/src/resolvers/statusResolver.ts index 9d3d1e8..14c8490 100644 --- a/service/src/resolvers/statusResolver.ts +++ b/service/src/resolvers/statusResolver.ts @@ -8,11 +8,18 @@ const moistureFactorMultiplier = 1.5 const limitFactor = curry(Math.min)(scale.length - 1) -const resolveStatus = (soilMoisture: number, windSpeed: number) => { +const resolveStatus = (soilMoisture: number, windSpeed: number, temp: number) => { const moistureFactor = (soilMoisture / (moistureLimit / 2)) * moistureFactorMultiplier const windFactor = windSpeed / (windLimit / 2) + const temperaturFactor = + temp < 5 ? 3 : + temp < 10 ? 2 : + temp < 15 ? 1.5 : + temp < 20 ? 1 : + temp < 25 ? 0 : 0 + const index = pipe( - () => (moistureFactor + windFactor) - 1, + () => (moistureFactor + windFactor + temperaturFactor) - 1, Math.round, limitFactor ) diff --git a/service/src/service/agro.ts b/service/src/service/agro.ts index daa4483..d0f712c 100644 --- a/service/src/service/agro.ts +++ b/service/src/service/agro.ts @@ -1,25 +1,13 @@ -import maybe, { Maybe } from 'https://raw.githubusercontent.com/MergHQ/denofun/maybe-get-or-else/lib/maybe.ts' import memoize from 'https://raw.githubusercontent.com/MergHQ/denofun/memoize-ttl/lib/memoize.ts' import { checkError } from '../error.ts' -import resolveStatus from '../resolvers/statusResolver.ts' const baseUrl = 'http://api.agromonitoring.com/agro/1.0' -const buildUrlString = (polyId: Maybe , appId: Maybe) => (resource: string) => { - const resolvedPolygonId = - polyId - .map(p => `polyid=${p}`) - .getOrElse('') +const buildUrlString = (polyId: string , appId: string) => (resource: string) => + `${baseUrl}/${resource}?polyid=${polyId}&appid=${appId}` - const resolvedAppId = - appId - .map(a => `appid=${a}`) - .getOrElse('') - - return `${baseUrl}/${resource}?${resolvedPolygonId}&${resolvedAppId}` -} const cacheTTL = 60000 -const withIdentifiers = buildUrlString(maybe(Deno.env.get('POLY_ID')), maybe(Deno.env.get('AGRO_API_TOKEN'))) +const withResource = buildUrlString(Deno.env.get('POLY_ID')!, Deno.env.get('AGRO_API_TOKEN')!) interface SoilApiResponse { dt: number, @@ -44,23 +32,22 @@ const parseSoilResult = ({ dt, t10, moisture, t0 }: SoilApiResponse): SoilMoistu }) const fetchSoilMoisture = () => - fetch(withIdentifiers('soil')) + fetch(withResource('soil')) .then(checkError) .then((data: SoilApiResponse) => parseSoilResult(data)) const fetchWindSpeed = () => - fetch(withIdentifiers('weather')) + fetch(withResource('weather')) .then(checkError) .then(({ wind }: WeatherApiResponse) => wind.speed) const cachedSoilMoisture = memoize(fetchSoilMoisture, cacheTTL) const cachedWindSpeed = memoize(fetchWindSpeed, cacheTTL) -export const fetchCurrentStatus = () => +export const fetchCurrentData = () => Promise.all([cachedSoilMoisture(), cachedWindSpeed()]) .then(([moistureData, windSpeed]) => ({ updated: new Date(moistureData.dt), - status: resolveStatus(moistureData.moisture, windSpeed), details: { groundMoisture: moistureData.moisture, windSpeed diff --git a/service/src/service/darksky.ts b/service/src/service/darksky.ts new file mode 100644 index 0000000..937265c --- /dev/null +++ b/service/src/service/darksky.ts @@ -0,0 +1,25 @@ +import memoize from 'https://raw.githubusercontent.com/MergHQ/denofun/memoize-ttl/lib/memoize.ts' +import { checkError } from '../error.ts' + +const hki = '60.169940,24.938679' +const chaceTTL = 120000 +const url = `https://api.darksky.net/forecast/${Deno.env.get('DARKSKY_TOKEN')!}/${hki}?units=si` + +interface DarkSkyResponse { + currently: { + time: number, + temperature: number + } +} + +const fetchTemp = (): Promise<{ temp: number, updated: Date }> => + fetch(url) + .then(checkError) + .then((data: DarkSkyResponse) => ({ + updated: new Date(data.currently.time * 1000), + temp: data.currently.temperature + })) + +const cached = memoize(fetchTemp, chaceTTL) + +export const fetchCached = cached