Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make position optional #39

Merged
merged 9 commits into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed .eslintignore
Empty file.
77 changes: 0 additions & 77 deletions .eslintrc.js

This file was deleted.

4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ Once installed, restart your node-red server, and you will have a set of new nod

# Setup
![image of configuration](images/small-timer-config.png)<br>
Start by configuring a position, this is used to calculate the correct sunrise/sunset times for your area. You can either let your browser do it by pressing the button "Get position from browser" or use other means like Google Maps to find the latitude/longitude for your area.
_Optional_: Start by configuring your location, which is used to calculate the correct sunrise and sunset times for your area. You can either let your browser do this by clicking the "Get position from browser" button, or manually enter the latitude and longitude using a service like Google Maps.

If you don't configure a location, you'll only be able to use fixed times to send on/off messages.

## On and Off time
Configures the on and off events<br>
Expand Down
72 changes: 72 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import typescriptEslint from '@typescript-eslint/eslint-plugin'
import _import from 'eslint-plugin-import'
import importNewlines from 'eslint-plugin-import-newlines'
import { fixupPluginRules } from '@eslint/compat'
import globals from 'globals'
import tsParser from '@typescript-eslint/parser'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import js from '@eslint/js'
import { FlatCompat } from '@eslint/eslintrc'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
})

export default [
...compat.extends('eslint:recommended', 'plugin:@typescript-eslint/recommended'),
{
plugins: {
'@typescript-eslint': typescriptEslint,
import: fixupPluginRules(_import),
'import-newlines': importNewlines,
},

languageOptions: {
globals: {
...globals.node,
},

parser: tsParser,
ecmaVersion: 'latest',
sourceType: 'module',
},

rules: {
'import/order': 'off',
'eol-last': 'error',
'comma-dangle': ['warn', 'always-multiline'],

indent: ['error', 4, {
SwitchCase: 1,
}],

'linebreak-style': ['error', 'unix'],

quotes: ['warn', 'single', {
avoidEscape: true,
}],

semi: ['warn', 'never'],

'max-len': ['error', {
code: 180,
}],

'no-console': ['warn'],
curly: ['error'],
eqeqeq: ['error'],
complexity: ['error', 11],

'import-newlines/enforce': ['error', {
items: 2,
'max-len': 180,
semi: false,
}],
},
},
]
44 changes: 24 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"author": {
"name": "Thomas Bowman Mørch"
},
"version": "0.18.0",
"version": "0.19.0",
"engines": {
"node": ">=14.0.0"
},
Expand Down Expand Up @@ -57,34 +57,38 @@
"url": "git+https://github.com/tbowmo/node-red-small-timer.git"
},
"dependencies": {
"@node-red/util": "^3.1.8",
"date-fns": "^3.6.0",
"@node-red/util": "^3.1.14",
"date-fns": "^4.1.0",
"suncalc": "^1.9.0"
},
"devDependencies": {
"@types/chai": "^4.3.14",
"@types/mocha": "^10.0.6",
"@types/node": "^20.12.2",
"@eslint/compat": "1.2.1",
"@eslint/eslintrc": "3.1.0",
"@eslint/js": "9.13.0",
"@types/chai": "^4.3.20",
"@types/mocha": "^10.0.9",
"@types/node": "^20.16.13",
"@types/node-red": "^1.3.5",
"@types/node-red-node-test-helper": "^0.3.4",
"@types/suncalc": "^1.9.2",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"chai": "^4.4.1",
"eslint": "^8.57.0",
"eslint-plugin-import": "^2.29.1",
"@typescript-eslint/eslint-plugin": "^8.10.0",
"@typescript-eslint/parser": "^8.10.0",
"chai": "^4.5.0",
"eslint": "^9.13.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-import-newlines": "^1.4.0",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"mocha": "^10.4.0",
"node-red": "^3.1.8",
"node-red-node-test-helper": "^0.3.3",
"nyc": "^15.1.0",
"prettier": "^3.2.5",
"sinon": "^17.0.1",
"globals": "15.11.0",
"husky": "^9.1.6",
"lint-staged": "^15.2.10",
"mocha": "^10.7.3",
"node-red": "^3.1.14",
"node-red-node-test-helper": "^0.3.4",
"nyc": "^17.1.0",
"prettier": "^3.3.3",
"sinon": "^19.0.2",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.2",
"typescript": "^5.4.3"
"typescript": "^5.6.3"
},
"packageManager": "yarn@3.5.1"
}
2 changes: 1 addition & 1 deletion src/lib/small-timer-runner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ describe('lib/small-timer-runner', () => {
stubs.stubbedTimeCalc.getTimeToNextEndEvent.returns(20)
stubs.stubbedTimeCalc.getOnState.returns(false)

const runner = new SmallTimerRunner(stubs.position, stubs.configuration, stubs.node)
const runner = new SmallTimerRunner(undefined, stubs.configuration, stubs.node)
sinon.clock.tick(80000)

sinon.assert.calledWithExactly(stubs.status, { fill: 'red', shape: 'dot', text: 'OFF for 00secs' })
Expand Down
40 changes: 20 additions & 20 deletions src/lib/small-timer-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const SecondsTick = 1000

export class SmallTimerRunner {

private startupTock: ReturnType<typeof setTimeout> | undefined = undefined
private readonly startupTock: ReturnType<typeof setTimeout> | undefined = undefined

// Timing variables
private tickTimer: ReturnType<typeof setInterval> | undefined = undefined
Expand All @@ -38,34 +38,34 @@ export class SmallTimerRunner {
private override: State = 'auto'
private currentState = false

private topic: string
private onMsg: string
private offMsg: string
private onMsgType: string
private offMsgType: string
private rules: Rule[]
private repeat: boolean
private repeatInterval: number
private onTimeout: number
private offTimeout: number
private readonly topic: string
private readonly onMsg: string
private readonly offMsg: string
private readonly onMsgType: string
private readonly offMsgType: string
private readonly rules: Rule[]
private readonly repeat: boolean
private readonly repeatInterval: number
private readonly onTimeout: number
private readonly offTimeout: number

private timeCalc: TimeCalc
private debugMode = false
private readonly timeCalc: TimeCalc
private readonly debugMode: boolean

private timer = new Timer()
private sendEmptyPayload: boolean
private readonly timer = new Timer()
private readonly sendEmptyPayload: boolean

// Default to 20 seconds between ticks (update of state / node)
private defaultTickTimer = SecondsTick * 20
private readonly defaultTickTimer = SecondsTick * 20

constructor(
position: Position,
position: Position | undefined,
configuration: ISmallTimerProperties,
private node: NodeFunctions,
private readonly node: NodeFunctions,
) {
this.timeCalc = new TimeCalc(
Number(position.latitude),
Number(position.longitude),
position ? Number(position.latitude) : undefined,
position ? Number(position.longitude) : undefined,
configuration.wrapMidnight,
Number(configuration.startTime),
Number(configuration.endTime),
Expand Down
11 changes: 7 additions & 4 deletions src/lib/sun-and-moon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,15 @@ export class SunAndMoon {
* @param wrapMidnight
*/
constructor(
protected latitude: number,
protected longitude: number,
protected readonly latitude?: number,
protected readonly longitude?: number,
) {
}

public getTimes(now = new Date()): {id: string, label: string, date: Date}[] {
if (!this.latitude || !this.longitude) {
return []
}
this.sunTimes = SunCalc.getTimes(now, this.latitude, this.longitude)
this.moonTimes = SunCalc.getMoonTimes(now, this.latitude, this.longitude)

Expand All @@ -67,7 +70,7 @@ export class SunAndMoon {
return
}
const labelParts = key.split(/(?=[A-Z])/)
let label = labelParts.join(' ').toLocaleLowerCase()
let label = labelParts.join(' ').toLocaleLowerCase()
if (this.sunTimes && key in this.sunTimes) {
label = capitalizeFirstLetter(label)
const date = this.sunTimes[(key as SunTimes)]
Expand Down Expand Up @@ -106,7 +109,7 @@ export class SunAndMoon {

protected updateSunCalc(now = new Date()) {
// Only necessary to do the calculations once a day
if (this.lastSunCalcUpdate === now.getDay()) {
if (this.lastSunCalcUpdate === now.getDay() || !this.latitude || !this.longitude) {
return
}

Expand Down
25 changes: 22 additions & 3 deletions src/lib/time-calculation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ describe('lib/time-calculation', () => {
const minutes = currentTime.getHours() * 60 + currentTime.getMinutes()

const timeCalc = new TimeCalc(
10,
10,
undefined,
undefined,
false,
minutes - 120, // 09:00
minutes + 120, // 12:00
Expand All @@ -45,7 +45,7 @@ describe('lib/time-calculation', () => {
0,
)

sinon.assert.calledWith(stubs.getTimes, currentTime, 10, 10)
sinon.assert.notCalled(stubs.getTimes)
expect(timeCalc.getOnState()).to.equal(true)
expect(timeCalc.getTimeToNextStartEvent()).to.equal(1320)
expect(timeCalc.getTimeToNextEndEvent()).to.equal(120)
Expand Down Expand Up @@ -202,6 +202,25 @@ describe('lib/time-calculation', () => {
.to.throw('Can\'t look up the correct time \'6001\' \'0\'')
})

it.skip('should throw error if position is not set and dynamic time is requested', () => {
setupTest()
sinon.clock.setSystemTime(new Date('2023-01-01 13:00'))

const timeCalc = new TimeCalc(
undefined,
undefined,
true,
5000,
5001,
0,
0,
0,
)

expect(timeCalc.setStartEndTime.bind(timeCalc, 5101, 5102))
.to.throw('Something went wrong, latitude and longitude not specified')
})

it('should create data suitable for debug', () => {
setupTest()
sinon.clock.setSystemTime(new Date('2023-01-01 13:00'))
Expand Down
Loading
Loading