Compare commits

..

33 Commits

Author SHA1 Message Date
Koushik Dutta
8e31b5f970 homekit: fixup exports, publish 2025-01-24 10:52:26 -08:00
Nick Berardi
0873a72848 homekit: moved humidity settings to common and added characteristics to expose settings Home Assistant (#1699) 2025-01-24 10:51:28 -08:00
Koushik Dutta
145c66e1c8 doorbird: publish 2025-01-24 10:15:04 -08:00
r3dDoX
2b60b45113 doorbird: update underlying doorbird api package (#1705) 2025-01-24 10:12:51 -08:00
Koushik Dutta
6f63927e2f core: publish 2025-01-23 19:34:41 -08:00
Koushik Dutta
528eabdfc0 sdk: improve StorageSettings deviceFilter 2025-01-23 19:33:42 -08:00
Koushik Dutta
e201ea1fc1 doorbird: fix build 2025-01-23 13:11:31 -08:00
Koushik Dutta
7790810b86 server: cleanup launch.json 2025-01-23 09:23:13 -08:00
Koushik Dutta
e9ec78909b core: Fix missing buttons 2025-01-22 13:46:38 -08:00
Koushik Dutta
26245e17ca core: publish button support 2025-01-22 13:22:49 -08:00
Koushik Dutta
5d87a1b2dd sdk: PressButtons 2025-01-22 12:57:27 -08:00
Koushik Dutta
e1efde3868 postbeta 2025-01-22 12:00:35 -08:00
Koushik Dutta
525eb028c6 sdk: Buttons interface 2025-01-22 10:14:42 -08:00
Koushik Dutta
520c6a62a1 Merge branch 'main' of github.com:koush/scrypted 2025-01-21 13:48:43 -08:00
Koushik Dutta
6e6898ce33 common/rebroadcast: change rtp packet size to 32000 since that is what is supported on darwin for some reason 2025-01-21 13:48:38 -08:00
Koushik Dutta
1344c9112c server: fixup potential unhandled errors in sdk fork 2025-01-21 09:50:44 -08:00
Koushik Dutta
f2148ce26a hikvision: publish 2025-01-20 19:37:37 -08:00
Koushik Dutta
81b00195d6 Merge branch 'main' of github.com:koush/scrypted 2025-01-20 19:36:58 -08:00
Koushik Dutta
8f71778f05 core: publish 2025-01-20 19:36:54 -08:00
George Talusan
2e5b8d90aa hikvision: add ERI-K104-P4 to the list of NVRs that doesn't support channel cap checks (#1698) 2025-01-19 00:32:36 -08:00
Koushik Dutta
780182b94a fix npm-install.sh 2025-01-18 15:04:59 -08:00
Brett Jia
57480f7606 actions: add Linux arm64 runner to tests (#1696) 2025-01-17 16:50:35 -08:00
Koushik Dutta
1478684120 Update install-nvidia-container-toolkit.sh 2025-01-17 14:58:45 -08:00
Koushik Dutta
223b302bed core: publish new ui with lxc-docker update fix 2025-01-16 13:28:28 -08:00
Koushik Dutta
f56cef1b50 postbeta 2025-01-16 12:04:53 -08:00
Koushik Dutta
83bfa30d4b server: improve abi/server change detection 2025-01-16 12:04:43 -08:00
Koushik Dutta
611674af46 rebroadcast: publish 2025-01-16 08:24:01 -08:00
Koushik Dutta
941ea7f346 Update bug_report.md 2025-01-16 08:06:59 -08:00
Koushik Dutta
2b9c2956d6 Update bug_report.md 2025-01-16 08:05:28 -08:00
Koushik Dutta
266d5bf8a3 Update bug_report.md 2025-01-16 07:19:41 -08:00
Koushik Dutta
d0007fc7bb postbeta 2025-01-15 14:53:20 -08:00
Koushik Dutta
75f90b78eb postrelease 2025-01-15 14:53:20 -08:00
Simon Marty
1e8959413e Fix path in comment (#1694) 2025-01-15 14:43:37 -08:00
35 changed files with 440 additions and 222 deletions

View File

@@ -27,6 +27,11 @@ Created issues that do not meet these requirements or are improperly filled out
1. Delete this section and everything above it.
2. Fill out the sections below.
** Before You Submit**
- [ ] I checked that my issue isn't already filed: [Search open issues](https://github.com/koush/scrypted/issues).
- [ ] I checked the relevant camera/device and/or plugin `Log` in the `Management Console` for errors or warnings that may help identify and resolve the issue myself.
**Describe the bug**
A clear and concise description of what the bug is. The issue tracker is only for reporting bugs in Scrypted, for general support check Discord. Hardrware support requests or assistance requests will be immediately closed.
@@ -43,6 +48,9 @@ A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Logs**
Include a `Log` from the device/camera in the management console (and if applicable, the affacted plugin, like HomeKit).
**Server (please complete the following information):**
- OS: [e.g. Ubuntu]
- Installation Method: [e.g. Desktop App, Docker, Local]

View File

@@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
runner: [ubuntu-latest, macos-14, macos-13, windows-latest]
runner: [ubuntu-latest, ubuntu-24.04-arm, macos-14, macos-13, windows-latest]
steps:
- name: Checkout repository

View File

@@ -247,7 +247,8 @@ export function createRtspParser(options?: StreamParserOptions): RtspStreamParse
'tcp',
...(options?.vcodec || []),
...(options?.acodec || []),
'-pkt_size', '64000',
// linux and windows seem to support 64000 but darwin is 32000?
'-pkt_size', '32000',
'-f', 'rtsp',
],
findSyncFrame(streamChunks: StreamChunk[]) {

View File

@@ -55,7 +55,7 @@ services:
# Scrypted NVR Storage (Part 3 of 3)
# Modify to add the additional volume for Scrypted NVR.
# The following example would mount the /mnt/sda/video path on the host
# The following example would mount the /mnt/media/video path on the host
# to the /nvr path inside the docker container.
# - /mnt/media/video:/nvr

View File

@@ -36,9 +36,8 @@ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --yes --dea
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
apt -y update
# is there a way to get a versioned package automatically?
apt -y install nvidia-utils-560
apt -y install cuda-drivers
apt -y install nvidia-container-toolkit
nvidia-ctk runtime configure --runtime=docker
nvidia-ctk config --set nvidia-container-cli.no-cgroups --in-place
systemctl restart docker

View File

@@ -27,7 +27,7 @@ echo "external/werift > npm install"
npm install
popd
for directory in rtsp amcrest onvif hikvision reolink unifi-protect webrtc homekit
for directory in rtsp ffmpeg-camera amcrest onvif hikvision reolink unifi-protect webrtc homekit
do
echo "$directory > npm install"
pushd plugins/$directory

View File

@@ -1,25 +1,25 @@
{
"name": "@scrypted/client",
"version": "1.3.9",
"version": "1.3.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/client",
"version": "1.3.9",
"version": "1.3.10",
"license": "ISC",
"dependencies": {
"@scrypted/types": "^0.3.92",
"engine.io-client": "^6.6.1",
"@scrypted/types": "^0.3.100",
"engine.io-client": "^6.6.2",
"follow-redirects": "^1.15.9",
"rimraf": "^6.0.1"
},
"devDependencies": {
"@types/ip": "^1.1.3",
"@types/node": "^22.7.4",
"@types/node": "^22.10.7",
"@types/ws": "^8.5.13",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
"typescript": "^5.7.3"
}
},
"node_modules/@cspotcode/source-map-support": {
@@ -76,9 +76,9 @@
}
},
"node_modules/@scrypted/types": {
"version": "0.3.92",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.92.tgz",
"integrity": "sha512-/M1Lg42/yoFWusj5+Lyp2S0JCiWDDWcmsjiUnTf1DahZ6/M2oZ3bwR/0KX3D9vJE79owWST1Gm0+Rdvpxuil9A==",
"version": "0.3.100",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.100.tgz",
"integrity": "sha512-s/07QCxjMWqODgWj2UpLehzeo2cGFrCA9X8mvpG3owT/+q+sb8v/UUcw9TLHGSN6yIriNhceg3i9WO07kEIT6A==",
"license": "ISC"
},
"node_modules/@socket.io/component-emitter": {
@@ -120,12 +120,13 @@
}
},
"node_modules/@types/node": {
"version": "22.7.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz",
"integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==",
"version": "22.10.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz",
"integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
"undici-types": "~6.20.0"
}
},
"node_modules/@types/ws": {
@@ -272,9 +273,10 @@
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
"node_modules/engine.io-client": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.1.tgz",
"integrity": "sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw==",
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.2.tgz",
"integrity": "sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
@@ -623,10 +625,11 @@
}
},
"node_modules/typescript": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -636,10 +639,11 @@
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/client",
"version": "1.3.9",
"version": "1.3.10",
"description": "",
"main": "dist/packages/client/src/index.js",
"scripts": {
@@ -13,14 +13,14 @@
"license": "ISC",
"devDependencies": {
"@types/ip": "^1.1.3",
"@types/node": "^22.7.4",
"@types/node": "^22.10.7",
"@types/ws": "^8.5.13",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
"typescript": "^5.7.3"
},
"dependencies": {
"@scrypted/types": "^0.3.92",
"engine.io-client": "^6.6.1",
"@scrypted/types": "^0.3.100",
"engine.io-client": "^6.6.2",
"follow-redirects": "^1.15.9",
"rimraf": "^6.0.1"
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/core",
"version": "0.3.103",
"version": "0.3.108",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/core",
"version": "0.3.103",
"version": "0.3.108",
"license": "Apache-2.0",
"dependencies": {
"@scrypted/common": "file:../../common",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/core",
"version": "0.3.103",
"version": "0.3.108",
"description": "Scrypted Core plugin. Provides the UI, websocket, and engine.io APIs.",
"author": "Scrypted",
"license": "Apache-2.0",

View File

@@ -1,19 +1,19 @@
{
"name": "@scrypted/doorbird",
"version": "0.0.2",
"version": "0.0.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/doorbird",
"version": "0.0.2",
"version": "0.0.4",
"dependencies": {
"doorbird": "^2.1.2"
"doorbird": "2.6.0"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^18.15.11",
"@types/node": "^22.10.10",
"cross-env": "^7.0.3"
}
},
@@ -24,36 +24,41 @@
"license": "ISC",
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^5.0.1",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^5.3.3"
"typescript": "^5.5.3"
},
"devDependencies": {
"@types/node": "^20.10.8",
"@types/node": "^20.11.0",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.4",
"version": "0.3.108",
"dev": true,
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
"scrypted-changelog": "bin/scrypted-changelog.js",
@@ -65,11 +70,9 @@
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"stringify-object": "^3.3.0",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21"
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.11"
}
},
"node_modules/@scrypted/common": {
@@ -81,10 +84,14 @@
"link": true
},
"node_modules/@types/node": {
"version": "18.15.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
"dev": true
"version": "22.10.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz",
"integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
@@ -92,11 +99,12 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.4",
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@@ -145,10 +153,11 @@
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -167,25 +176,29 @@
}
},
"node_modules/doorbird": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/doorbird/-/doorbird-2.1.2.tgz",
"integrity": "sha512-ivwwsS/nOslDnuLg3UB60Axo76w5LQuZ67mCPEeWFr5+HbGYRL7PCY3iLjWYaIakh5+IvZyFPHKR4yHAvAc1WQ==",
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/doorbird/-/doorbird-2.6.0.tgz",
"integrity": "sha512-HZBI5uFhwEVF8JFULQlpzXXvjSHmtQMJUNWfogq6vHe3kv7mCSmg0g/TDbeV5fVvisi8w7GxKD0/PpZCrtcGOg==",
"dependencies": {
"axios": "^1.2.1",
"axios": "^1.6.2",
"chacha-js": "^2.1.1",
"libsodium-wrappers-sumo": "^0.7.11"
"libsodium-wrappers-sumo": "^0.7.13"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/follow-redirects": {
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
@@ -225,16 +238,16 @@
"dev": true
},
"node_modules/libsodium-sumo": {
"version": "0.7.11",
"resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.11.tgz",
"integrity": "sha512-bY+7ph7xpk51Ez2GbE10lXAQ5sJma6NghcIDaSPbM/G9elfrjLa0COHl/7P6Wb/JizQzl5UQontOOP1z0VwbLA=="
"version": "0.7.15",
"resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.15.tgz",
"integrity": "sha512-5tPmqPmq8T8Nikpm1Nqj0hBHvsLFCXvdhBFV7SGOitQPZAA6jso8XoL0r4L7vmfKXr486fiQInvErHtEvizFMw=="
},
"node_modules/libsodium-wrappers-sumo": {
"version": "0.7.11",
"resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.11.tgz",
"integrity": "sha512-DGypHOmJbB1nZn89KIfGOAkDgfv5N6SBGC3Qvmy/On0P0WD1JQvNRS/e3UL3aFF+xC0m+MYz5M+MnRnK2HMrKQ==",
"version": "0.7.15",
"resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.15.tgz",
"integrity": "sha512-aSWY8wKDZh5TC7rMvEdTHoyppVq/1dTSAeAR7H6pzd6QRT3vQWcT5pGwCotLcpPEOLXX6VvqihSPkpEhYAjANA==",
"dependencies": {
"libsodium-sumo": "^0.7.11"
"libsodium-sumo": "^0.7.15"
}
},
"node_modules/mime-db": {
@@ -307,6 +320,13 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/doorbird",
"version": "0.0.2",
"version": "0.0.4",
"scripts": {
"scrypted-setup-project": "scrypted-setup-project",
"prescrypted-setup-project": "scrypted-package-json",
@@ -33,12 +33,12 @@
]
},
"dependencies": {
"doorbird": "^2.1.2"
"doorbird": "2.6.0"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^18.15.11",
"@types/node": "^22.10.10",
"cross-env": "^7.0.3"
}
}

View File

@@ -1,13 +1,13 @@
import { listenZero } from '@scrypted/common/src/listen-cluster';
import sdk, { BinarySensor, Camera, DeviceProvider, DeviceCreator, DeviceCreatorSettings, DeviceInformation, FFmpegInput, Intercom, MediaObject, PictureOptions, ResponseMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, VideoCamera, MotionSensor } from '@scrypted/sdk';
import child_process, { ChildProcess } from 'child_process';
import { ffmpegLogInitialOutput, safePrintFFmpegArguments } from "@scrypted/common/src/media-helpers";
import net from 'net';
import { randomBytes } from 'crypto';
import { PassThrough, Readable } from "stream";
import { readLength } from "@scrypted/common/src/read-stream";
import { authHttpFetch } from "@scrypted/common/src/http-auth-fetch";
import { ApiRingEvent, ApiMotionEvent, DoorbirdAPI } from "./doorbird-api";
import { listenZero } from '@scrypted/common/src/listen-cluster';
import { ffmpegLogInitialOutput, safePrintFFmpegArguments } from "@scrypted/common/src/media-helpers";
import { readLength } from "@scrypted/common/src/read-stream";
import sdk, { BinarySensor, Camera, DeviceCreator, DeviceCreatorSettings, DeviceInformation, DeviceProvider, FFmpegInput, Intercom, MediaObject, MotionSensor, PictureOptions, ResponseMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, VideoCamera } from '@scrypted/sdk';
import child_process, { ChildProcess } from 'child_process';
import { randomBytes } from 'crypto';
import net from 'net';
import { PassThrough, Readable } from "stream";
import { ApiMotionEvent, ApiRingEvent, DoorbirdAPI } from "./doorbird-api";
const { deviceManager, mediaManager } = sdk;
@@ -384,7 +384,7 @@ class DoorbirdCamera extends ScryptedDeviceBase implements Intercom, Camera, Vid
this.console.log('Doorbird: timed out waiting for tcp client from ffmpeg');
server.close();
}, 30000);
const port = await listenZero(server);
const port = await listenZero(server, '127.0.0.1');
return port;
}

View File

@@ -1,5 +1,6 @@
{
"compilerOptions": {
"module": "Node16",
"target": "esnext",
"moduleResolution": "Node16",
"esModuleInterop": true,

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.160",
"version": "0.0.161",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/hikvision",
"version": "0.0.160",
"version": "0.0.161",
"license": "Apache",
"dependencies": {
"@scrypted/common": "file:../../common",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.160",
"version": "0.0.161",
"description": "Hikvision Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -116,11 +116,15 @@ export class HikvisionCameraAPI implements HikvisionAPI {
}
async checkIsOldModel() {
// The old Hikvision DS-7608NI-E2 doesn't support channel capability checks, and the requests cause errors
// The old Hikvision NVRs don't support channel capability checks, and the requests cause errors
const oldModels = [
/DS-76098NI-E2/,
/ERI-K104-P4/
];
const model = await this.checkDeviceModel();
if (!model)
return;
return !!model?.match(/DS-7608NI-E2/);
return !!oldModels.find(oldModel => model?.match(oldModel));
}
async checkStreamSetup(channel: string, isOld: boolean): Promise<HikvisionCameraStreamSetup> {

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/homekit",
"version": "1.2.62",
"version": "1.2.63",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/homekit",
"version": "1.2.62",
"version": "1.2.63",
"dependencies": {
"@koush/werift-src": "file:../../external/werift",
"check-disk-space": "^3.4.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/homekit",
"version": "1.2.62",
"version": "1.2.63",
"description": "HomeKit Plugin for Scrypted",
"scripts": {
"scrypted-setup-project": "scrypted-setup-project",

View File

@@ -1,4 +1,4 @@
import sdk, { AirQuality, AirQualitySensor, CO2Sensor, DeviceProvider, Fan, FanMode, NOXSensor, OnOff, PM10Sensor, PM25Sensor, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, VOCSensor } from "@scrypted/sdk";
import sdk, { AirQuality, AirQualitySensor, CO2Sensor, DeviceProvider, Fan, FanMode, HumidityMode, HumiditySensor, HumiditySetting, HumiditySettingStatus, NOXSensor, OnOff, PM10Sensor, PM25Sensor, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, VOCSensor } from "@scrypted/sdk";
import { bindCharacteristic } from "../common";
import { Accessory, Characteristic, CharacteristicEventTypes, Service, uuid } from '../hap';
import type { HomeKitPlugin } from "../main";
@@ -96,24 +96,161 @@ export function addCarbonDioxideSensor(device: ScryptedDevice & CO2Sensor, acces
return co2Service;
}
export function addFan(device: ScryptedDevice & Fan & OnOff, accessory: Accessory): Service {
if (!device.interfaces.includes(ScryptedInterface.OnOff) && !device.interfaces.includes(ScryptedInterface.Fan))
function commonHumidifierDehumidifier(mode: HumidityMode, subtype: string, name: string, device: ScryptedDevice & HumiditySetting & HumiditySensor, accessory: Accessory): Service {
function currentState(mode: HumidityMode) {
switch(mode) {
case HumidityMode.Humidify:
return Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING;
case HumidityMode.Dehumidify:
return Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING;
case HumidityMode.Off:
return Characteristic.CurrentHumidifierDehumidifierState.INACTIVE;
default:
return Characteristic.CurrentHumidifierDehumidifierState.IDLE;
}
}
function targetState(mode: HumidityMode) {
switch(mode) {
case HumidityMode.Humidify:
return Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER;
case HumidityMode.Dehumidify:
return Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER;
default:
return Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER;
}
}
const service = accessory.addService(Service.HumidifierDehumidifier, name, subtype);
bindCharacteristic(device, ScryptedInterface.HumiditySetting, service, Characteristic.Active,
() => {
if (!device.humiditySetting?.mode)
return false;
if (device.humiditySetting.mode === mode)
return true;
if (device.humiditySetting.mode === HumidityMode.Auto)
return true;
return false;
});
service.getCharacteristic(Characteristic.Active).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setHumidity({
mode: value ? mode : HumidityMode.Off
});
});
bindCharacteristic(device, ScryptedInterface.HumiditySensor, service, Characteristic.CurrentRelativeHumidity,
() => device.humidity);
bindCharacteristic(device, ScryptedInterface.HumiditySetting, service, Characteristic.CurrentHumidifierDehumidifierState,
() => currentState(device.humiditySetting?.activeMode));
bindCharacteristic(device, ScryptedInterface.HumiditySetting, service, Characteristic.TargetHumidifierDehumidifierState,
() => targetState(device.humiditySetting?.mode));
service.getCharacteristic(Characteristic.TargetHumidifierDehumidifierState).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setHumidity({
mode: value === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER
? HumidityMode.Humidify
: value === Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER
? HumidityMode.Dehumidify
: HumidityMode.Auto
});
});
function targetHumidity(setting: HumiditySettingStatus) {
if (!setting)
return 0;
if (setting?.availableModes.includes(HumidityMode.Humidify)
&& setting?.availableModes.includes(HumidityMode.Dehumidify)) {
if (setting?.activeMode === HumidityMode.Humidify)
return setting?.humidifierSetpoint;
if (setting?.activeMode === HumidityMode.Dehumidify)
return setting?.dehumidifierSetpoint;
return 0;
}
if (setting?.availableModes.includes(HumidityMode.Humidify))
return setting?.humidifierSetpoint;
if (setting?.availableModes.includes(HumidityMode.Dehumidify))
return setting?.dehumidifierSetpoint;
return 0;
}
bindCharacteristic(device, ScryptedInterface.HumiditySetting, service, Characteristic.TargetRelativeHumidity,
() => targetHumidity(device.humiditySetting));
return service;
}
function addHumidifier(device: ScryptedDevice & HumiditySetting & HumiditySensor, accessory: Accessory): Service {
var service = commonHumidifierDehumidifier(HumidityMode.Humidify, "humidifier", device.name + " Humidifier", device, accessory);
bindCharacteristic(device, ScryptedInterface.HumiditySetting, service, Characteristic.RelativeHumidityHumidifierThreshold,
() => device.humiditySetting?.humidifierSetpoint);
service.getCharacteristic(Characteristic.RelativeHumidityHumidifierThreshold).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setHumidity({
humidifierSetpoint: value as number,
});
});
return service;
}
function addDehumidifer(device: ScryptedDevice & HumiditySetting & HumiditySensor, accessory: Accessory): Service {
var service = commonHumidifierDehumidifier(HumidityMode.Dehumidify, "dehumidifier", device.name + " Dehumidifier", device, accessory);
bindCharacteristic(device, ScryptedInterface.HumiditySetting, service, Characteristic.RelativeHumidityDehumidifierThreshold,
() => device.humiditySetting?.dehumidifierSetpoint);
service.getCharacteristic(Characteristic.RelativeHumidityDehumidifierThreshold).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setHumidity({
dehumidifierSetpoint: value as number,
});
});
return service;
}
export function addHumiditySetting(device: ScryptedDevice & HumiditySetting & HumiditySensor, accessory: Accessory): Service {
if (!device.interfaces.includes(ScryptedInterface.HumiditySetting) && !device.interfaces.includes(ScryptedInterface.HumiditySensor))
return undefined;
var service;
if (device.humiditySetting?.availableModes.includes(HumidityMode.Humidify)) {
service = addHumidifier(device, accessory);
}
if (device.humiditySetting?.availableModes.includes(HumidityMode.Dehumidify)) {
service = addDehumidifer(device, accessory);
}
return service;
}
export function addFan(device: ScryptedDevice & Fan, accessory: Accessory): Service {
if (!device.interfaces.includes(ScryptedInterface.Fan))
return undefined;
const service = accessory.addService(Service.Fanv2, device.name);
if (device.interfaces.includes(ScryptedInterface.OnOff)) {
bindCharacteristic(device, ScryptedInterface.OnOff, service, Characteristic.Active,
() => !!device.on);
bindCharacteristic(device, ScryptedInterface.OnOff, service, Characteristic.Active,
() => device.fan?.active);
service.getCharacteristic(Characteristic.Active).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
if (value)
device.turnOn();
else
device.turnOff();
service.getCharacteristic(Characteristic.Active).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setFan({
mode: value ? FanMode.Auto : FanMode.Manual,
});
}
});
if (device.fan?.counterClockwise !== undefined) {
bindCharacteristic(device, ScryptedInterface.Fan, service, Characteristic.RotationDirection,

View File

@@ -1,7 +1,7 @@
import { Fan, FanMode, HumidityMode, HumiditySensor, HumiditySetting, OnOff, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, TemperatureSetting, TemperatureUnit, Thermometer, ThermostatMode, AirQualitySensor, AirQuality, PM10Sensor, PM25Sensor, VOCSensor, NOXSensor, CO2Sensor } from '@scrypted/sdk';
import { Fan, FanMode, HumidityMode, HumiditySensor, HumiditySetting, OnOff, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, TemperatureSetting, TemperatureUnit, Thermometer, ThermostatMode, AirQualitySensor, AirQuality, PM10Sensor, PM25Sensor, VOCSensor, NOXSensor, CO2Sensor, HumiditySettingStatus } from '@scrypted/sdk';
import { addSupportedType, bindCharacteristic, DummyDevice, } from '../common';
import { Characteristic, CharacteristicEventTypes, CharacteristicSetCallback, CharacteristicValue, Service } from '../hap';
import { addAirQualitySensor, addCarbonDioxideSensor, addFan, makeAccessory } from './common';
import { addAirQualitySensor, addCarbonDioxideSensor, addFan, addHumiditySetting, makeAccessory } from './common';
import type { HomeKitPlugin } from "../main";
addSupportedType({
@@ -178,72 +178,60 @@ addSupportedType({
() => device.humidity || 0);
}
if (device.interfaces.includes(ScryptedInterface.HumiditySetting) && device.interfaces.includes(ScryptedInterface.HumiditySensor)) {
const humidityService = accessory.addService(Service.HumidifierDehumidifier);
// add fan state to thermostat service even though it is not required or optional,
// in order to expose to Home Assistant HomeKit Controller under their climate entity
if (device.interfaces.includes(ScryptedInterface.Fan)) {
bindCharacteristic(device, ScryptedInterface.Fan, service, Characteristic.TargetFanState,
() => device.fan?.mode === FanMode.Manual
? Characteristic.TargetFanState.MANUAL
: Characteristic.TargetFanState.AUTO);
bindCharacteristic(device, ScryptedInterface.HumiditySetting, humidityService, Characteristic.Active,
() => {
if (!device.humiditySetting?.mode)
return false;
if (device.humiditySetting.mode === HumidityMode.Off)
return false;
return true;
});
humidityService.getCharacteristic(Characteristic.Active).on(CharacteristicEventTypes.SET, (value, callback) => {
service.getCharacteristic(Characteristic.TargetFanState).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setHumidity({
mode: value ? HumidityMode.Auto : HumidityMode.Off
device.setFan({
mode: value === Characteristic.TargetFanState.MANUAL ? FanMode.Manual : FanMode.Auto,
});
});
bindCharacteristic(device, ScryptedInterface.HumiditySensor, humidityService, Characteristic.CurrentRelativeHumidity,
() => device.humidity || 0);
bindCharacteristic(device, ScryptedInterface.HumiditySetting, humidityService, Characteristic.CurrentHumidifierDehumidifierState,
() => !device.humiditySetting?.activeMode
? Characteristic.CurrentHumidifierDehumidifierState.INACTIVE
: device.humiditySetting.activeMode === HumidityMode.Dehumidify
? Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING
: device.humiditySetting.activeMode === HumidityMode.Humidify
? Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING
: Characteristic.CurrentHumidifierDehumidifierState.IDLE);
bindCharacteristic(device, ScryptedInterface.HumiditySetting, humidityService, Characteristic.TargetHumidifierDehumidifierState,
() => !device.humiditySetting?.mode || device.humiditySetting?.mode === HumidityMode.Auto
? Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER
: device.humiditySetting?.mode === HumidityMode.Dehumidify
? Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER
: Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER);
humidityService.getCharacteristic(Characteristic.TargetHumidifierDehumidifierState).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setHumidity({
mode: value === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER
? HumidityMode.Humidify
: value === Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER
? HumidityMode.Dehumidify
: HumidityMode.Auto
});
});
bindCharacteristic(device, ScryptedInterface.HumiditySetting, humidityService, Characteristic.RelativeHumidityHumidifierThreshold,
() => device.humiditySetting?.humidifierSetpoint || 0);
humidityService.getCharacteristic(Characteristic.RelativeHumidityHumidifierThreshold).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setHumidity({
humidifierSetpoint: value as number,
});
});
bindCharacteristic(device, ScryptedInterface.HumiditySetting, humidityService, Characteristic.RelativeHumidityDehumidifierThreshold,
() => device.humiditySetting?.dehumidifierSetpoint || 0);
humidityService.getCharacteristic(Characteristic.RelativeHumidityDehumidifierThreshold).on(CharacteristicEventTypes.SET, (value, callback) => {
callback();
device.setHumidity({
dehumidifierSetpoint: value as number,
});
});
bindCharacteristic(device, ScryptedInterface.Fan, service, Characteristic.CurrentFanState,
() => !device.fan?.active
? Characteristic.CurrentFanState.INACTIVE
: !device.fan.speed
? Characteristic.CurrentFanState.IDLE
: Characteristic.CurrentFanState.BLOWING_AIR);
}
// add relataive target humidity to thermostat service even though it is not required or optional,
// in order to expose to Home Assistant HomeKit Controller under their climate entity
if (device.interfaces.includes(ScryptedInterface.HumiditySetting)) {
function targetHumidity(setting: HumiditySettingStatus) {
if (!setting)
return 0;
if (setting?.availableModes.includes(HumidityMode.Humidify)
&& setting?.availableModes.includes(HumidityMode.Dehumidify)) {
if (setting?.activeMode === HumidityMode.Humidify)
return setting?.humidifierSetpoint;
if (setting?.activeMode === HumidityMode.Dehumidify)
return setting?.dehumidifierSetpoint;
return 0;
}
if (setting?.availableModes.includes(HumidityMode.Humidify))
return setting?.humidifierSetpoint;
if (setting?.availableModes.includes(HumidityMode.Dehumidify))
return setting?.dehumidifierSetpoint;
return 0;
}
bindCharacteristic(device, ScryptedInterface.HumiditySetting, service, Characteristic.TargetRelativeHumidity,
() => targetHumidity(device.humiditySetting));
}
addHumiditySetting(device, accessory);
addFan(device, accessory);
addAirQualitySensor(device, accessory);
addCarbonDioxideSensor(device, accessory);

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/prebuffer-mixin",
"version": "0.10.43",
"version": "0.10.45",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/prebuffer-mixin",
"version": "0.10.43",
"version": "0.10.45",
"license": "Apache-2.0",
"dependencies": {
"@scrypted/common": "file:../../common",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/prebuffer-mixin",
"version": "0.10.43",
"version": "0.10.45",
"description": "Video Stream Rebroadcast, Prebuffer, and Management Plugin for Scrypted.",
"author": "Scrypted",
"license": "Apache-2.0",

4
sdk/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/sdk",
"version": "0.3.106",
"version": "0.3.108",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/sdk",
"version": "0.3.106",
"version": "0.3.108",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.26.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/sdk",
"version": "0.3.106",
"version": "0.3.108",
"description": "",
"main": "dist/src/index.js",
"exports": {

View File

@@ -1,4 +1,4 @@
import sdk, { ScryptedInterface, Setting, Settings, SettingValue } from ".";
import sdk, { ScryptedDeviceType, ScryptedInterface, Setting, Settings, SettingValue } from ".";
const { systemManager } = sdk;
@@ -57,9 +57,9 @@ function parseValue(value: string | null | undefined, setting: StorageSetting, r
return value || readDefaultValue();
}
export type HideFunction = (device: any) => boolean;
export interface StorageSetting extends Omit<Setting, 'deviceFilter'> {
deviceFilter?: string | ((test: { id: string, deviceInterface: string, interfaces: string[], type: ScryptedDeviceType, ScryptedDeviceType: typeof ScryptedDeviceType, ScryptedInterface: typeof ScryptedInterface }) => boolean);
export interface StorageSetting extends Setting {
defaultValue?: any;
persistedDefaultValue?: any;
onPut?: (oldValue: any, newValue: any) => void;
@@ -140,7 +140,9 @@ export class StorageSettings<T extends string> implements Settings {
continue;
s.key = key;
s.value = this.getItemInternal(key as T, s, true);
ret.push(s);
if (typeof s.deviceFilter === 'function')
s.deviceFilter = s.deviceFilter.toString();
ret.push(s as Setting);
delete s.onPut;
delete s.onGet;
delete s.mapPut;

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/types",
"version": "0.3.98",
"version": "0.3.100",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/types",
"version": "0.3.98",
"version": "0.3.100",
"license": "ISC"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/types",
"version": "0.3.98",
"version": "0.3.100",
"description": "",
"main": "dist/index.js",
"author": "",

View File

@@ -117,6 +117,7 @@ class ScryptedInterface(str, Enum):
BinarySensor = "BinarySensor"
Brightness = "Brightness"
BufferConverter = "BufferConverter"
Buttons = "Buttons"
Camera = "Camera"
Charger = "Charger"
ClusterForkInterface = "ClusterForkInterface"
@@ -166,6 +167,7 @@ class ScryptedInterface(str, Enum):
PM25Sensor = "PM25Sensor"
PositionSensor = "PositionSensor"
PowerSensor = "PowerSensor"
PressButtons = "PressButtons"
Program = "Program"
PushHandler = "PushHandler"
Readme = "Readme"
@@ -951,7 +953,7 @@ class TamperState(TypedDict):
pass
TYPES_VERSION = "0.3.98"
TYPES_VERSION = "0.3.100"
class AirPurifier:
@@ -1006,6 +1008,10 @@ class BufferConverter:
pass
class Buttons:
buttons: list[str]
class Camera:
"""Camera devices can take still photos."""
@@ -1376,6 +1382,12 @@ class PowerSensor:
powerDetected: bool
class PressButtons:
async def pressButton(self, button: str) -> None:
pass
class Program:
async def run(self, variables: Any = None) -> Any:
@@ -1864,6 +1876,7 @@ class ScryptedInterfaceProperty(str, Enum):
colorTemperature = "colorTemperature"
rgb = "rgb"
hsv = "hsv"
buttons = "buttons"
running = "running"
paused = "paused"
docked = "docked"
@@ -1924,6 +1937,7 @@ class ScryptedInterfaceMethods(str, Enum):
setColorTemperature = "setColorTemperature"
setRgb = "setRgb"
setHsv = "setHsv"
pressButton = "pressButton"
sendNotification = "sendNotification"
start = "start"
stop = "stop"
@@ -2178,6 +2192,14 @@ class DeviceState:
def hsv(self, value: ColorHsv):
self.setScryptedProperty("hsv", value)
@property
def buttons(self) -> list[str]:
return self.getScryptedProperty("buttons")
@buttons.setter
def buttons(self, value: list[str]):
self.setScryptedProperty("buttons", value)
@property
def running(self) -> bool:
return self.getScryptedProperty("running")
@@ -2612,6 +2634,20 @@ ScryptedInterfaceDescriptors = {
"hsv"
]
},
"Buttons": {
"name": "Buttons",
"methods": [],
"properties": [
"buttons"
]
},
"PressButtons": {
"name": "PressButtons",
"methods": [
"pressButton"
],
"properties": []
},
"Notifier": {
"name": "Notifier",
"methods": [

View File

@@ -214,6 +214,14 @@ export interface ColorHsv {
v?: number;
}
export interface Buttons {
buttons?: ('doorbell' | string)[];
}
export interface PressButtons {
pressButton(button: string): Promise<void>;
}
export interface NotificationAction {
action: string;
icon?: string;
@@ -2255,6 +2263,8 @@ export enum ScryptedInterface {
ColorSettingTemperature = "ColorSettingTemperature",
ColorSettingRgb = "ColorSettingRgb",
ColorSettingHsv = "ColorSettingHsv",
Buttons = "Buttons",
PressButtons = "PressButtons",
Notifier = "Notifier",
StartStop = "StartStop",
Pause = "Pause",

View File

@@ -99,11 +99,6 @@
"env": {
"SCRYPTED_PYTHON310_PATH": "/opt/homebrew/bin/python3.10",
"DYLD_LIBRARY_PATH": "/usr/local/lib",
"SCRYPTED_CLUSTER_WORKER_NAME": "Macaroni 2",
"SCRYPTED_CLUSTER_LABELS": "@scrypted/coreml,@scrypted/tensorflow-lite,compute,compute.preferred",
"SCRYPTED_CLUSTER_MODE": "client",
"SCRYPTED_CLUSTER_SERVER": "192.168.2.130",
"SCRYPTED_CLUSTER_SECRET": "swordfish",
"SCRYPTED_CAN_RESTART": "true",
"SCRYPTED_VOLUME": "/Users/koush/.scrypted-cluster/volume-client",
}

View File

@@ -1,18 +1,18 @@
{
"name": "@scrypted/server",
"version": "0.125.3",
"version": "0.128.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/server",
"version": "0.125.3",
"version": "0.128.3",
"hasInstallScript": true,
"license": "ISC",
"dependencies": {
"@scrypted/ffmpeg-static": "^6.1.0-build3",
"@scrypted/node-pty": "^1.0.22",
"@scrypted/types": "^0.3.92",
"@scrypted/types": "^0.3.100",
"adm-zip": "^0.5.16",
"body-parser": "^1.20.3",
"cookie-parser": "^1.4.7",
@@ -557,9 +557,9 @@
}
},
"node_modules/@scrypted/types": {
"version": "0.3.92",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.92.tgz",
"integrity": "sha512-/M1Lg42/yoFWusj5+Lyp2S0JCiWDDWcmsjiUnTf1DahZ6/M2oZ3bwR/0KX3D9vJE79owWST1Gm0+Rdvpxuil9A==",
"version": "0.3.100",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.100.tgz",
"integrity": "sha512-s/07QCxjMWqODgWj2UpLehzeo2cGFrCA9X8mvpG3owT/+q+sb8v/UUcw9TLHGSN6yIriNhceg3i9WO07kEIT6A==",
"license": "ISC"
},
"node_modules/@types/adm-zip": {

View File

@@ -1,11 +1,11 @@
{
"name": "@scrypted/server",
"version": "0.127.1",
"version": "0.128.3",
"description": "",
"dependencies": {
"@scrypted/ffmpeg-static": "^6.1.0-build3",
"@scrypted/node-pty": "^1.0.22",
"@scrypted/types": "^0.3.92",
"@scrypted/types": "^0.3.100",
"adm-zip": "^0.5.16",
"body-parser": "^1.20.3",
"cookie-parser": "^1.4.7",

View File

@@ -4,7 +4,6 @@ import fs from 'fs';
import os from 'os';
import path from 'path';
import process from 'process';
import semver from 'semver';
import { ensurePluginVolume } from "./plugin-volume";
export function defaultNpmExec(args: string[], options: child_process.SpawnOptions) {
@@ -26,8 +25,16 @@ export function setNpmExecFunction(f: typeof npmExecFunction) {
export function getPluginNodePath(name: string) {
const pluginVolume = ensurePluginVolume(name);
const nodeMajorVersion = semver.parse(process.version).major;
let nodeVersionedDirectory = `node${nodeMajorVersion}-${process.platform}-${process.arch}`;
const abi = process.versions.modules;
let runtime = process.env.npm_config_runtime;
if (!runtime && process.versions.electron)
runtime = 'electron';
if (!runtime)
runtime = 'node';
const { platform, arch } = process;
let nodeVersionedDirectory = `n-${runtime}-v${abi}-${platform}-${arch}`;
const scryptedBase = process.env.SCRYPTED_BASE_VERSION;
if (scryptedBase)
nodeVersionedDirectory += '-' + scryptedBase;
@@ -98,7 +105,7 @@ export async function installOptionalDependencies(console: Console, packageJson:
if (!de.isDirectory())
return;
if (de.name.startsWith('linux') || de.name.startsWith('darwin') || de.name.startsWith('win32')
|| de.name.startsWith('python') || de.name.startsWith('node')) {
|| de.name.startsWith('python') || de.name.startsWith('node') || de.name.startsWith('n-')) {
console.log('Removing old dependencies:', filePath);
try {
await fs.promises.rm(filePath, {

View File

@@ -24,6 +24,7 @@ import { NodeThreadWorker } from './runtime/node-thread-worker';
import { prepareZip } from './runtime/node-worker-common';
import { getBuiltinRuntimeHosts } from './runtime/runtime-host';
import { RuntimeWorker, RuntimeWorkerOptions } from './runtime/runtime-worker';
import { Deferred } from '../deferred';
const serverVersion = require('../../package.json').version;
@@ -291,6 +292,14 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
forkPeer = Promise.resolve(localPeer);
}
const exitDeferred = new Deferred<string>();
runtimeWorker.on('exit', () => {
exitDeferred.resolve('worker exited');
});
runtimeWorker.on('error', e => {
exitDeferred.resolve('worker error' + e);
});
// thread workers inherit main console. pipe anything else.
if (!(runtimeWorker instanceof NodeThreadWorker)) {
const console = options?.id ? getMixinConsole(options.id, options.nativeId) : undefined;
@@ -299,6 +308,9 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
const result = (async () => {
const threadPeer = await forkPeer;
exitDeferred.promise.then(reason => {
threadPeer.kill(reason);
});
// todo: handle nested forks and skip wrap. this is probably buggy.
class PluginForkAPI extends PluginAPIProxy {
@@ -319,13 +331,7 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
const remote = await setupPluginRemote(threadPeer, forkApi, pluginId, { serverVersion }, () => systemManager.getSystemState());
forks.add(remote);
runtimeWorker.on('exit', () => {
threadPeer.kill('worker exited');
forkApi.removeListeners();
forks.delete(remote);
});
runtimeWorker.on('error', e => {
threadPeer.kill('worker error ' + e);
exitDeferred.promise.then(reason => {
forkApi.removeListeners();
forks.delete(remote);
});