Skip to content

Commit

Permalink
Make position optional (#39)
Browse files Browse the repository at this point in the history
* Make position optional
* Update readme file and other minor things
* Upgrade dependencies
* Maintainability fixes
* Bump version for release

---------

Co-authored-by: Thomas Bowman Mørch <[email protected]>
  • Loading branch information
tbowmo and Thomas Bowman Mørch authored Oct 20, 2024
1 parent c6ea187 commit af3938f
Show file tree
Hide file tree
Showing 13 changed files with 1,818 additions and 1,310 deletions.
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": "[email protected]"
}
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

0 comments on commit af3938f

Please sign in to comment.