diff --git a/package-lock.json b/package-lock.json index 9c35e81..5f96f98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "devDependencies": { "@faker-js/faker": "^10.0.0", "@types/express": "^5.0.3", + "@types/node": "^25.6.0", "@types/node-cron": "^3.0.11", "@types/play-sound": "^1.1.2", "@vitest/coverage-v8": "^3.2.4", @@ -1684,13 +1685,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.19.0" } }, "node_modules/@types/node-cron": { @@ -5958,9 +5959,9 @@ } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 00c2eb6..fd914ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osb-action-button", - "version": "0.0.0", + "version": "1.0.1", "type": "commonjs", "scripts": { "dev": "ts-node-dev --respawn ./src/sounder.ts", @@ -17,6 +17,7 @@ "devDependencies": { "@faker-js/faker": "^10.0.0", "@types/express": "^5.0.3", + "@types/node": "^25.6.0", "@types/node-cron": "^3.0.11", "@types/play-sound": "^1.1.2", "@vitest/coverage-v8": "^3.2.4", diff --git a/src/button.ts b/src/button.ts index 093da86..e41c3cc 100644 --- a/src/button.ts +++ b/src/button.ts @@ -9,6 +9,7 @@ import {getConfig} from './utils/config' import {updateConfig} from './bin/update-config' import {buttonApi} from './utils/button-api' import {VERSION} from './constants' +import {setState, getState} from './utils/button-state' const {writeFile} = fs.promises @@ -40,7 +41,7 @@ export const button = async () => { } } - const newConfig = await updateConfig() + const newConfig = await updateConfig(false) if (newConfig.ledPin !== config.ledPin) { ledInterface.setLEDPin(newConfig.ledPin) @@ -65,7 +66,7 @@ export const button = async () => { let holdTimeout: Timeout | null = null let cancelled: boolean = false - let buttonPressed: number = new Date().getTime() + setState(false) btn.watch(async (err, value) => { if (err) { @@ -76,7 +77,9 @@ export const button = async () => { if (value === 1) { // Button has been pressed. await log('👇 Button Pressed') - buttonPressed = new Date().getTime() + + // Set the button press state to true. + setState(true) if (triggerTimeout && !triggerTimeout._destroyed) { // There is currently a trigger timeout, clear it and return the LED to on. @@ -106,15 +109,23 @@ export const button = async () => { If the button was not last pressed within double the hold duration (or 10 seconds) ignore this release. */ - const releaseBuffer = + /*const releaseBuffer = config.holdDuration === 0 ? 10 : config.holdDuration * 2 if (buttonPressed < new Date().getTime() - releaseBuffer * 1000) { await log( `⚠️ Button press was more than ${releaseBuffer} seconds ago, ignoring release.` ) return + }*/ + + if (getState() === false) { + // The button state is currently false (not pressed) so should not have been releasable + await log(`⚠️ Button was released while not pressed.`) } + // This is a valid release so set the state to false, before any of the early returns + setState(false) + if (holdTimeout && !holdTimeout._destroyed) { // There is a hold timeout that can be cleared clearTimeout(holdTimeout) diff --git a/src/constants.ts b/src/constants.ts index 5a52d11..b1ade3e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1 +1 @@ -export const VERSION = '1.0.0' +export const VERSION = '1.0.1' diff --git a/src/utils/button-state.ts b/src/utils/button-state.ts new file mode 100644 index 0000000..dc01a02 --- /dev/null +++ b/src/utils/button-state.ts @@ -0,0 +1,17 @@ +declare global { + // This prevents us from making multiple connections to the db when the + // require cache is cleared. + var __buttonState: boolean | undefined +} + +const defaultButtonState = false + +export const getState = () => { + return global.__buttonState !== undefined + ? global.__buttonState + : defaultButtonState +} + +export const setState = (newState: boolean) => { + global.__buttonState = newState +} diff --git a/tsconfig.json b/tsconfig.json index b300526..b99d3e1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -34,7 +34,9 @@ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + "types": [ + "node" + ] /* Specify type package names to be included without being referenced in a source file. */, // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ @@ -111,4 +113,4 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ } -} \ No newline at end of file +}