diff --git a/.github/workflows/test-and-release.yml b/.github/workflows/test-and-release.yml index cee039cfd..e07aa6275 100644 --- a/.github/workflows/test-and-release.yml +++ b/.github/workflows/test-and-release.yml @@ -6,226 +6,226 @@ name: Test and Release # Run this job on all pushes and pull requests # as well as tags with a semantic version on: - push: - branches: - - master - tags: - # normal versions - - "v?[0-9]+.[0-9]+.[0-9]+" - # pre-releases - - "v?[0-9]+.[0-9]+.[0-9]+-**" - pull_request: {} + push: + branches: + - master + tags: + # normal versions + - 'v?[0-9]+.[0-9]+.[0-9]+' + # pre-releases + - 'v?[0-9]+.[0-9]+.[0-9]+-**' + pull_request: {} # Cancel previous PR/branch runs when a new commit is pushed concurrency: - group: ${{ github.ref }} - cancel-in-progress: true + group: ${{ github.ref }} + cancel-in-progress: true jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - - name: 'Install' - run: | - npm i -f - - - name: 'Install Adapter' - run: npm i -w packages/admin -f - - - name: 'Install FE' - run: | - cd packages/admin/src-admin - npm i -f - - - name: 'Lint Backend' - run: npm run lint-backend -w packages/admin - - - name: 'Build backend' - run: npm run build:backend -w packages/admin - - - name: 'Build JsonConfig' - run: npm run build -w packages/jsonConfig - - - name: 'Build dm-gui-components' - run: npm run build -w packages/dm-gui-components - - - name: Check TypeScript files - run: | - cd packages/admin/src-admin - npm run check-ts - - - name: 'Build' - run: | - npm run clean - NODE_OPTIONS=--max_old_space_size=4096 npm run build - - # Runs adapter tests on all supported node versions and OSes - adapter-tests: - if: contains(github.event.head_commit.message, '[skip ci]') == false - - needs: [build] - - runs-on: ${{ matrix.os }} - strategy: - matrix: - node-version: [18.x, 20.x, 22.4.1] - os: [ubuntu-latest, windows-latest, macos-latest] - - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - - name: Install Dependencies - run: npm i -f - - - name: 'Build backend' - run: npm run build:backend -w packages/admin - - - name: Run local tests - run: npm test -w packages/admin/ - - adapter-tests-gui: - if: contains(github.event.head_commit.message, '[skip ci]') == false - - needs: [build] - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Use Node.js 20.x - uses: actions/setup-node@v4 - with: - node-version: 20.x - - - name: Install Dependencies - run: npm run install-monorepo - - - name: 'Build backend' - run: npm run build:backend -w packages/admin - - - name: Build - run: NODE_OPTIONS=--max_old_space_size=8192 npm run build - - - name: Run GUI tests - run: npm run test:gui -w packages/admin/ - - - name: Archive screenshots - if: always() - # if: failure() - uses: actions/upload-artifact@v4 - with: - path: packages/admin/tmp/screenshots/**/*.png - retention-days: 3 - - auto-merge: - if: | - always() && - github.event_name == 'pull_request' - needs: [adapter-tests-gui] - runs-on: macos-latest # ubuntu-latest has too few RAM - - steps: - - id: automerge - name: automerge - uses: "pascalgn/automerge-action@v0.16.3" - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - MERGE_LABELS: "automated pr 🔧" - MERGE_FILTER_AUTHOR: "foxriver76" - MERGE_FORKS: "false" - MERGE_DELETE_BRANCH: "false" - UPDATE_LABELS: "automated pr 🔧" - MERGE_METHOD: "squash" - MERGE_COMMIT_MESSAGE: "pull-request-title-and-description" - - - name: Checkout repository - if: steps.automerge.outputs.mergeResult == 'merged' - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Fetch the history, or this action won't work - ref: 'master' - - - name: Use Node.js 20 - if: steps.automerge.outputs.mergeResult == 'merged' - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Determine version - if: steps.automerge.outputs.mergeResult == 'merged' - id: version - uses: actions/github-script@v7 - with: - result-encoding: string - script: | - return require('./lerna.json').version; - - - name: Extract the commit body - if: steps.automerge.outputs.mergeResult == 'merged' - id: extract_release - # The body may be multiline, therefore we need to escape some characters - run: | - BODY=$(git show -s --format=%b) - BODY="${BODY//'%'/'%25'}" - BODY="${BODY//$'\n'/'%0A'}" - BODY="${BODY//$'\r'/'%0D'}" - echo "::set-output name=BODY::$BODY" - - - name: Install Dependencies - if: steps.automerge.outputs.mergeResult == 'merged' - run: npm run install-monorepo - - - name: 'Build backend' - if: steps.automerge.outputs.mergeResult == 'merged' - run: npm run build:backend -w packages/admin - - - name: Publish package to npm - if: steps.automerge.outputs.mergeResult == 'merged' - run: | - npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} - npm whoami - git checkout -- package-lock.json - npx lerna publish from-package --yes - - - name: Create Github Release - if: steps.automerge.outputs.mergeResult == 'merged' - uses: ncipollo/release-action@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag: v${{ steps.version.outputs.result }} - name: Release v${{ steps.version.outputs.result }} - draft: false - prerelease: ${{ contains(steps.version.outputs.result, '-') }} - body: ${{ steps.extract_release.outputs.BODY }} - - - name: Notify Sentry.io about the release - if: steps.automerge.outputs.mergeResult == 'merged' - run: | - cd packages/admin - npm i -g @sentry/cli - export SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} - export SENTRY_URL=https://sentry.iobroker.net - export SENTRY_ORG=iobroker - export SENTRY_PROJECT=iobroker-admin - export SENTRY_VERSION=iobroker.admin@${{ steps.version.outputs.result }} - export SENTRY_RELEASE=${{ steps.version.outputs.result }} - sentry-cli releases new $SENTRY_VERSION - sentry-cli releases finalize $SENTRY_VERSION - sentry-cli sourcemaps inject ./adminWww - sentry-cli sourcemaps upload ./adminWww - - # Add the following line BEFORE finalize if repositories are connected in Sentry - # sentry-cli releases set-commits $SENTRY_VERSION --auto - - # Add the following line BEFORE finalize if sourcemap uploads are needed - # sentry-cli releases files $SENTRY_VERSION upload-sourcemaps build/ + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20.x + + - name: 'Install' + run: | + npm i -f + + - name: 'Install Adapter' + run: npm i -w packages/admin -f + + - name: 'Install FE' + run: | + cd packages/admin/src-admin + npm i -f + + - name: 'Lint Backend' + run: npm run lint-backend -w packages/admin + + - name: 'Build backend' + run: npm run build:backend -w packages/admin + + - name: 'Build JsonConfig' + run: npm run build -w packages/jsonConfig + + - name: 'Build dm-gui-components' + run: npm run build -w packages/dm-gui-components + + - name: Check TypeScript files + run: | + cd packages/admin/src-admin + npm run check-ts + + - name: 'Build' + run: | + npm run clean + NODE_OPTIONS=--max_old_space_size=4096 npm run build + + # Runs adapter tests on all supported node versions and OSes + adapter-tests: + if: contains(github.event.head_commit.message, '[skip ci]') == false + + needs: [build] + + runs-on: ${{ matrix.os }} + strategy: + matrix: + node-version: [18.x, 20.x, 22.4.1] + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install Dependencies + run: npm i -f + + - name: 'Build backend' + run: npm run build:backend -w packages/admin + + - name: Run local tests + run: npm test -w packages/admin/ + + adapter-tests-gui: + if: contains(github.event.head_commit.message, '[skip ci]') == false + + needs: [build] + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20.x + + - name: Install Dependencies + run: npm run install-monorepo + + - name: 'Build backend' + run: npm run build:backend -w packages/admin + + - name: Build + run: NODE_OPTIONS=--max_old_space_size=8192 npm run build + + - name: Run GUI tests + run: npm run test:gui -w packages/admin/ + + - name: Archive screenshots + if: always() + # if: failure() + uses: actions/upload-artifact@v4 + with: + path: packages/admin/tmp/screenshots/**/*.png + retention-days: 3 + + auto-merge: + if: | + always() && + github.event_name == 'pull_request' + needs: [adapter-tests-gui] + runs-on: macos-latest # ubuntu-latest has too few RAM + + steps: + - id: automerge + name: automerge + uses: 'pascalgn/automerge-action@v0.16.4' + env: + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + MERGE_LABELS: 'automated pr 🔧' + MERGE_FILTER_AUTHOR: 'foxriver76' + MERGE_FORKS: 'false' + MERGE_DELETE_BRANCH: 'false' + UPDATE_LABELS: 'automated pr 🔧' + MERGE_METHOD: 'squash' + MERGE_COMMIT_MESSAGE: 'pull-request-title-and-description' + + - name: Checkout repository + if: steps.automerge.outputs.mergeResult == 'merged' + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch the history, or this action won't work + ref: 'master' + + - name: Use Node.js 20 + if: steps.automerge.outputs.mergeResult == 'merged' + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Determine version + if: steps.automerge.outputs.mergeResult == 'merged' + id: version + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + return require('./lerna.json').version; + + - name: Extract the commit body + if: steps.automerge.outputs.mergeResult == 'merged' + id: extract_release + # The body may be multiline, therefore we need to escape some characters + run: | + BODY=$(git show -s --format=%b) + BODY="${BODY//'%'/'%25'}" + BODY="${BODY//$'\n'/'%0A'}" + BODY="${BODY//$'\r'/'%0D'}" + echo "::set-output name=BODY::$BODY" + + - name: Install Dependencies + if: steps.automerge.outputs.mergeResult == 'merged' + run: npm run install-monorepo + + - name: 'Build backend' + if: steps.automerge.outputs.mergeResult == 'merged' + run: npm run build:backend -w packages/admin + + - name: Publish package to npm + if: steps.automerge.outputs.mergeResult == 'merged' + run: | + npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} + npm whoami + git checkout -- package-lock.json + npx lerna publish from-package --yes + + - name: Create Github Release + if: steps.automerge.outputs.mergeResult == 'merged' + uses: ncipollo/release-action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag: v${{ steps.version.outputs.result }} + name: Release v${{ steps.version.outputs.result }} + draft: false + prerelease: ${{ contains(steps.version.outputs.result, '-') }} + body: ${{ steps.extract_release.outputs.BODY }} + + - name: Notify Sentry.io about the release + if: steps.automerge.outputs.mergeResult == 'merged' + run: | + cd packages/admin + npm i -g @sentry/cli + export SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + export SENTRY_URL=https://sentry.iobroker.net + export SENTRY_ORG=iobroker + export SENTRY_PROJECT=iobroker-admin + export SENTRY_VERSION=iobroker.admin@${{ steps.version.outputs.result }} + export SENTRY_RELEASE=${{ steps.version.outputs.result }} + sentry-cli releases new $SENTRY_VERSION + sentry-cli releases finalize $SENTRY_VERSION + sentry-cli sourcemaps inject ./adminWww + sentry-cli sourcemaps upload ./adminWww + + # Add the following line BEFORE finalize if repositories are connected in Sentry + # sentry-cli releases set-commits $SENTRY_VERSION --auto + + # Add the following line BEFORE finalize if sourcemap uploads are needed + # sentry-cli releases files $SENTRY_VERSION upload-sourcemaps build/ diff --git a/CHANGELOG_OLD.md b/CHANGELOG_OLD.md index 6e6e268a5..e98cc0006 100644 --- a/CHANGELOG_OLD.md +++ b/CHANGELOG_OLD.md @@ -1,1674 +1,2105 @@ # Older changes +## 7.1.0 (2024-09-02) + +- (bluefox) Added the possibility to show button in notifications +- (bluefox) Removed gulp from the build process + ## 7.0.25 (2024-08-24) -* (bluefox) Improvement for automatic tests -* (bluefox) Added the possibility to style the response text for `textSendTo` in JSON Config + +- (bluefox) Improvement for automatic tests +- (bluefox) Added the possibility to style the response text for `textSendTo` in JSON Config ## 7.0.24 (2024-08-16) -* (bluefox) Showed min/max limits by controlling the values -* (bluefox) Corrected style for tabs + +- (bluefox) Showed min/max limits by controlling the values +- (bluefox) Corrected style for tabs ## 7.0.23 (2024-08-05) -* (foxriver76) only automatically open the host notification dialog if warnings are available -* (foxriver76) improved style of host notification dialog -* (foxriver76) clarified auto upgrade options selection -* (bluefox) Corrected the link in instances, e.g., for vis-2 -* (bluefox) Corrected the connection information in the instance tab + +- (foxriver76) only automatically open the host notification dialog if warnings are available +- (foxriver76) improved style of host notification dialog +- (foxriver76) clarified auto upgrade options selection +- (bluefox) Corrected the link in instances, e.g., for vis-2 +- (bluefox) Corrected the connection information in the instance tab ## 7.0.22 (2024-07-29) -* (bluefox) Corrected installation of adapter with the license unequal to MIT -* (bluefox) Corrected width of a side menu -* (bluefox) Allowed the pasting into object JSON editor + +- (bluefox) Corrected installation of adapter with the license unequal to MIT +- (bluefox) Corrected width of a side menu +- (bluefox) Allowed the pasting into object JSON editor ## 7.0.18 (2024-07-22) -* (bluefox) Corrected export from JSON table -* (foxriver76) added `qrCode` component to JSON config -* (bluefox) Corrected adding of adapters with licenses (other than MIT) -* (bluefox) Improved license dialog + +- (bluefox) Corrected export from JSON table +- (foxriver76) added `qrCode` component to JSON config +- (bluefox) Corrected adding of adapters with licenses (other than MIT) +- (bluefox) Improved license dialog ## 7.0.17 (2024-07-15) -* (bluefox) Corrected the CRON description -* (bluefox) Corrected the Device Manager Component + +- (bluefox) Corrected the CRON description +- (bluefox) Corrected the Device Manager Component ## 7.0.16 (2024-07-15) -* (bluefox) Allowed playing mp3 and video files in the file browser + +- (bluefox) Allowed playing mp3 and video files in the file browser ## 7.0.13 (2024-07-12) -* (bluefox) Do not send `sendto` requests if control is hidden -* (bluefox) Read recommended versions from `iobroker/iobroker` + +- (bluefox) Do not send `sendto` requests if control is hidden +- (bluefox) Read recommended versions from `iobroker/iobroker` ## 7.0.12 (2024-07-10) -* (bluefox) Changed a recommended node.js version from 18 to 20 + +- (bluefox) Changed a recommended node.js version from 18 to 20 ## 7.0.11 (2024-07-03) -* (foxriver76) host tab details are now indicated by a classic chevron instead of blink indicator -* (foxriver76) show js-controller changelog more prominent -* (bluefox) correcting the update button + +- (foxriver76) host tab details are now indicated by a classic chevron instead of blink indicator +- (foxriver76) show js-controller changelog more prominent +- (bluefox) correcting the update button ## 7.0.9 (2024-07-02) -* (bluefox) Improved the mobile object browser + +- (bluefox) Improved the mobile object browser ## 7.0.7 (2024-06-27) -* (bluefox) Corrected call of getObjectView with null parameter + +- (bluefox) Corrected call of getObjectView with null parameter ## 7.0.6 (2024-06-26) -* (bluefox) Login page was corrected -* (bluefox) Icons were corrected + +- (bluefox) Login page was corrected +- (bluefox) Icons were corrected ## 7.0.2 (2024-06-24) -* (bluefox) Working on Json-Custom-Components -* (foxriver76) on js-controller updater correctly determines the ip of slave hosts -* (foxriver76) removed "@iobroker/types" from production dependencies + +- (bluefox) Working on Json-Custom-Components +- (foxriver76) on js-controller updater correctly determines the ip of slave hosts +- (foxriver76) removed "@iobroker/types" from production dependencies ## 7.0.1 (2024-06-10) -* (bluefox) Because of the breaking change in GUI components, the GUI was updated. Users will see no difference, but developers should check their packages. -* (bluefox) Rewritten many GUI components to TypeScript -* (foxriver76) Added support for the adapter's auto-update option. New version of js-controller required. -* (bluefox) GUI was re-written to typescript to 100% -* (bluefox) Shows only installed adapters in the adapter tab or first 100 adapters + +- (bluefox) Because of the breaking change in GUI components, the GUI was updated. Users will see no difference, but developers should check their packages. +- (bluefox) Rewritten many GUI components to TypeScript +- (foxriver76) Added support for the adapter's auto-update option. New version of js-controller required. +- (bluefox) GUI was re-written to typescript to 100% +- (bluefox) Shows only installed adapters in the adapter tab or first 100 adapters ## 6.17.14 (2024-05-25) -* (bluefox) Only some packages updated + +- (bluefox) Only some packages updated ## 6.17.13 (2024-05-23) -* (bluefox) Alias editing corrected -* (bluefox) Web-extension indicator corrected + +- (bluefox) Alias editing corrected +- (bluefox) Web-extension indicator corrected ## 6.17.12 (2024-05-22) -* (foxriver76) support of Node.js upgrade via UI (with js-controller Kiera - v6) -* (bluefox) Corrected CRON settings + +- (foxriver76) support of Node.js upgrade via UI (with js-controller Kiera - v6) +- (bluefox) Corrected CRON settings ## 6.17.11 (2024-05-20) -* (bluefox) Corrected custom configuration dialog + +- (bluefox) Corrected custom configuration dialog ## 6.17.9 (2024-05-17) -* (bluefox) Corrected style of time picker in JSON config -* (bluefox) Corrected saving of tab color + +- (bluefox) Corrected style of time picker in JSON config +- (bluefox) Corrected saving of tab color ## 6.17.7 (2024-04-26) -* (bluefox) Improved category tab + +- (bluefox) Improved category tab ## 6.17.6 (2024-04-19) -* (bluefox) Extend the table JSON Config with the encryption possibility -* (bluefox) Do not read historical data if instance is not active + +- (bluefox) Extend the table JSON Config with the encryption possibility +- (bluefox) Do not read historical data if instance is not active ## 6.17.3 (2024-04-11) -* (foxriver76) fixed npm adapter installation + +- (foxriver76) fixed npm adapter installation ## 6.17.2 (2024-04-08) -* (foxriver76) avoid a crash case if a user has no permission to write objects + +- (foxriver76) avoid a crash case if a user has no permission to write objects ## 6.17.1 (2024-04-06) -* (bluefox) support of includes in JSONConfig files + +- (bluefox) support of includes in JSONConfig files ## 6.16.0 (2024-03-26) -* (foxriver76) added a new tab to the installation wizard which recommends common adapters -* (bluefox) applied newest adapter-react-v5 changes and types + +- (foxriver76) added a new tab to the installation wizard which recommends common adapters +- (bluefox) applied newest adapter-react-v5 changes and types ## 6.15.2 (2024-03-07) -* (foxriver76) fixed cron dialog + +- (foxriver76) fixed cron dialog ## 6.15.1 (2024-03-04) -* (foxriver76) fixed problem with saving array values in custom config -* (foxriver76) fixed issue on deleting objects -* (foxriver76) make UI update of controller and admin more verbose + +- (foxriver76) fixed problem with saving array values in custom config +- (foxriver76) fixed issue on deleting objects +- (foxriver76) make UI update of controller and admin more verbose ## 6.15.0 (2024-03-01) -* (foxriver76) harmonized the links to adapter documentation (and fallback to english if no explicit doc for sys language provided) -* (bluefox) added possibility to delete whole adapter from instance tab if only one instance left -* (foxriver76) new dialog for notifications introduced for non-system notifications (system notifications are still on hosts tab) -* (foxriver76) the new `licenseInformation` icon now changes color correctly with the theme + +- (foxriver76) harmonized the links to adapter documentation (and fallback to english if no explicit doc for sys language provided) +- (bluefox) added possibility to delete whole adapter from instance tab if only one instance left +- (foxriver76) new dialog for notifications introduced for non-system notifications (system notifications are still on hosts tab) +- (foxriver76) the new `licenseInformation` icon now changes color correctly with the theme ## 6.14.1 (2024-02-20) -* (foxriver76) align items better when adapter tab is used in row mode + +- (foxriver76) align items better when adapter tab is used in row mode ## 6.14.0 (2024-02-19) -* (foxriver76) adapters tab is now showing information from `licenseInformation` -* (foxriver76) show important notifications above changelog, so user reads them on update dialog + +- (foxriver76) adapters tab is now showing information from `licenseInformation` +- (foxriver76) show important notifications above changelog, so user reads them on update dialog ## 6.13.21 (2024-02-15) -* (foxriver76) do not crash when using the dropdown on multi edit custom settings + +- (foxriver76) do not crash when using the dropdown on multi edit custom settings ## 6.13.20 (2024-02-14) -* (foxriver76) after successful update via npm tab, perform an additional upload as `iob url` commands do not do it internally -* (foxriver76) fixed problem with saving on multi edit custom settings + +- (foxriver76) after successful update via npm tab, perform an additional upload as `iob url` commands do not do it internally +- (foxriver76) fixed problem with saving on multi edit custom settings ## 6.13.19 (2024-02-12) -* (foxriver76) generate notification if new adapter updates are available + +- (foxriver76) generate notification if new adapter updates are available ## 6.13.17 (2024-02-09) -* (foxriver76) fix date and time picker json config components showing current time even though the value is undefined -* (foxriver76) added new options for time picker json config component -* (foxriver76) fixed issue when exporting jsonConfig -* (klein0r) Allow to install specific version of adapter + +- (foxriver76) fix date and time picker json config components showing current time even though the value is undefined +- (foxriver76) added new options for time picker json config component +- (foxriver76) fixed issue when exporting jsonConfig +- (klein0r) Allow to install specific version of adapter ## 6.13.16 (2024-01-30) -* (foxriver76) allow to display and modify `ics` files -* (foxriver76) redirect correctly when exiting json config with unsaved changes + +- (foxriver76) allow to display and modify `ics` files +- (foxriver76) redirect correctly when exiting json config with unsaved changes ## 6.13.15 (2024-01-01) -* (foxriver76) fixed scrolling of Select ID dialogs + +- (foxriver76) fixed scrolling of Select ID dialogs ## 6.13.14 (2023-12-30) -* (foxriver76) internal optimizations + +- (foxriver76) internal optimizations ## 6.13.5 (2023-12-22) -* (foxriver76) bring back missing `crypto-js` -* (foxriver76) fix crash case due to global dependency check + +- (foxriver76) bring back missing `crypto-js` +- (foxriver76) fix crash case due to global dependency check ## 6.13.3 (2023-12-21) -* (foxriver76) fixed problem with default value of underscore attributes in Json Config -* (foxriver76) prevent strict schema validation being logged to syslog -* (foxriver76) fixed problems with ObjectCustomEditor -* (klein0r) fixed markdown links (if default branch main) -* (foxriver76) fixed global dependencies check + +- (foxriver76) fixed problem with default value of underscore attributes in Json Config +- (foxriver76) prevent strict schema validation being logged to syslog +- (foxriver76) fixed problems with ObjectCustomEditor +- (klein0r) fixed markdown links (if default branch main) +- (foxriver76) fixed global dependencies check ## 6.12.9 (2023-12-12) -* (foxriver76) prevented the strict schema validation being logged to syslog -* (bluefox) corrected the displaying of news with the new lines + +- (foxriver76) prevented the strict schema validation being logged to syslog +- (bluefox) corrected the displaying of news with the new lines ## 6.12.8 (2023-12-06) -* (bluefox) corrected ACL for files -* (bluefox) allowed changing color of the menu item -* (bluefox) corrected the user/group icon selector + +- (bluefox) corrected ACL for files +- (bluefox) allowed changing color of the menu item +- (bluefox) corrected the user/group icon selector ## 6.12.7 (2023-12-03) -* (foxriver76) add property `onLoaded` to `sendTo` json config -* (foxriver76) fixed easy admin height + +- (foxriver76) add property `onLoaded` to `sendTo` json config +- (foxriver76) fixed easy admin height ## 6.12.6 (2023-12-01) -* (foxriver76) fixed JSON config file component if no initial value exists -* (bluefox) added the creation of a state or of a device possibility to the context menu + +- (foxriver76) fixed JSON config file component if no initial value exists +- (bluefox) added the creation of a state or of a device possibility to the context menu ## 6.12.5 (2023-11-23) -* (foxriver76) fixed json config ConfigFileSelector -* (klein0r) fixed title bar layout with username and icon + +- (foxriver76) fixed json config ConfigFileSelector +- (klein0r) fixed title bar layout with username and icon ## 6.12.4 (2023-11-16) -* (foxriver76) custom settings icon has no a brighter color in dark mode -* (foxriver76) fixed color of host selector in dark mode -* (foxriver76) fixed problem with a JSON config language component + +- (foxriver76) custom settings icon has no a brighter color in dark mode +- (foxriver76) fixed color of host selector in dark mode +- (foxriver76) fixed problem with a JSON config language component ## 6.12.3 (2023-11-15) -* (foxriver76) fixed problem that disabled checkbox is still clickable -* (foxriver76) no longer replace valid `common.adminUI.tab` values of adapters -* (foxriver76) fixed `freeSolo` option for autocomplete components -* (foxriver76) fixed issue with jsonConfig `sendTo` with `native` option when returning multiple properties -* (foxriver76) fixed empty dropdown selection after selecting `system language` in JsonConfig + +- (foxriver76) fixed problem that disabled checkbox is still clickable +- (foxriver76) no longer replace valid `common.adminUI.tab` values of adapters +- (foxriver76) fixed `freeSolo` option for autocomplete components +- (foxriver76) fixed issue with jsonConfig `sendTo` with `native` option when returning multiple properties +- (foxriver76) fixed empty dropdown selection after selecting `system language` in JsonConfig ## 6.12.2 (2023-11-02) -* (foxriver76) fixed issue with jsonConfig `sendTo` with `native` option when returning multiple properties -* (foxriver76) fixed crash case when schema cannot be read -* (klein0r) Fixed noDelete attribute of JSON config accordion + +- (foxriver76) fixed issue with jsonConfig `sendTo` with `native` option when returning multiple properties +- (foxriver76) fixed crash case when schema cannot be read +- (klein0r) Fixed noDelete attribute of JSON config accordion ## 6.12.1 (2023-10-29) -* (foxriver76) optimzied the notificaiton popup (auto-extend first entry per category, respect line breaks, respect severity for icons) -* (theimo1221) Stabilize onObjectChange handling during creation of new objects in WebUi, to directly show new element. + +- (foxriver76) optimzied the notificaiton popup (auto-extend first entry per category, respect line breaks, respect severity for icons) +- (theimo1221) Stabilize onObjectChange handling during creation of new objects in WebUi, to directly show new element. ## 6.12.0 (2023-10-24) -* (foxriver76) fixed issue when updating news in backend -* (foxriver76) validate json config against the schema -* (foxriver76) update socket-client to improve performance + +- (foxriver76) fixed issue when updating news in backend +- (foxriver76) validate json config against the schema +- (foxriver76) update socket-client to improve performance ## 6.11.0 (2023-10-19) -* (foxriver76) jsonConfig type number now stores values as number instead of string -* (foxriver76) objects browser number value input behavior change to allow leading minus -* (bluefox) Added component `interfaces` to the JSON config -* (bluefox) Implemented Backend to GUI communication + +- (foxriver76) jsonConfig type number now stores values as number instead of string +- (foxriver76) objects browser number value input behavior change to allow leading minus +- (bluefox) Added component `interfaces` to the JSON config +- (bluefox) Implemented Backend to GUI communication ## 6.10.9 (2023-10-16) -* (bluefox) Improvement of the public accessibility check + +- (bluefox) Improvement of the public accessibility check ## 6.10.8 (2023-10-13) -* (foxriver76) update adapter-react-v5 to fix issues with object browser + +- (foxriver76) update adapter-react-v5 to fix issues with object browser ## 6.10.7 (2023-10-11) -* (bluefox) Corrected adapter termination if the alias has no target + +- (bluefox) Corrected adapter termination if the alias has no target ## 6.10.6 (2023-10-11) -* (bluefox) Added possibility to show the icon on JSON config tabs -* (foxriver76) on upgrade all, not yet started commands can now be aborted -* (bluefox) Added security check if the server is available from the internet without protection -* (bluefox) Corrected navigation after the settings closing + +- (bluefox) Added possibility to show the icon on JSON config tabs +- (foxriver76) on upgrade all, not yet started commands can now be aborted +- (bluefox) Added security check if the server is available from the internet without protection +- (bluefox) Corrected navigation after the settings closing ## 6.10.5 (2023-10-10) -* (foxriver76) JSON config component `port` does no longer mark port as occupied if it is only occupied on another host -* (foxriver76) register news as notifications -* (foxriver76) if upgrade all is stopped on error, activate close button -* (bluefox) Export/import objects with its values + +- (foxriver76) JSON config component `port` does no longer mark port as occupied if it is only occupied on another host +- (foxriver76) register news as notifications +- (foxriver76) if upgrade all is stopped on error, activate close button +- (bluefox) Export/import objects with its values ## 6.10.4 (2023-09-25) -* (foxriver76) fixed parsing `jsonConfig` + +- (foxriver76) fixed parsing `jsonConfig` ## 6.10.3 (2023-09-25) -* (foxriver76) fixed `installedFrom` other source indicator not shown on adapter's tab -* (foxriver76) allowed using enter key to save changes in object edit dialog -* (foxriver76) fixed json config crash with empty table + +- (foxriver76) fixed `installedFrom` other source indicator not shown on adapter's tab +- (foxriver76) allowed using enter key to save changes in object edit dialog +- (foxriver76) fixed json config crash with empty table ## 6.10.2 (2023-09-20) -* (foxriver76) harmonized data on csv export with actual data shown by admin -* (foxriver76) on expert mode installation tab, on no selection deactivate install button -* (foxriver76) ensure the latest version is installed on `npm install` -* (foxriver76) optimized enum objects -* (foxriver76) disallow Google Translate as the plugin causes crash cases -* (foxriver76) fixed crash on intro tab on docker hosts -* (foxriver76) fixed crash case on invalid state objects + +- (foxriver76) harmonized data on csv export with actual data shown by admin +- (foxriver76) on expert mode installation tab, on no selection deactivate install button +- (foxriver76) ensure the latest version is installed on `npm install` +- (foxriver76) optimized enum objects +- (foxriver76) disallow Google Translate as the plugin causes crash cases +- (foxriver76) fixed crash on intro tab on docker hosts +- (foxriver76) fixed crash case on invalid state objects ## 6.10.1 (2023-09-11) -* (foxriver76) fixed `between` function for showing news -* (foxriver76) if date string is not parseable show the original string instead of `Invalid Date` -* (foxriver76) updated socket classes to not crash on invalid patterns + +- (foxriver76) fixed `between` function for showing news +- (foxriver76) if date string is not parseable show the original string instead of `Invalid Date` +- (foxriver76) updated socket classes to not crash on invalid patterns ## 6.10.0 (2023-09-08) -* (foxriver76) various minor improvements -* (foxriver76) fixed problem with discovery dialog -* (foxriver76) object browser now validates setting state of type number -* (foxriver76) allow to specify unique columns for tables -* (foxriver76) fix crash on invalid states, which are missing the property `common.role` + +- (foxriver76) various minor improvements +- (foxriver76) fixed problem with discovery dialog +- (foxriver76) object browser now validates setting state of type number +- (foxriver76) allow to specify unique columns for tables +- (foxriver76) fix crash on invalid states, which are missing the property `common.role` ## 6.9.2 (2023-09-01) -* (foxriver76) show info if server time differs from client time -* (foxriver76) remove confusion with different names for state (datapoint and state) -* (jogibear9988) fixed link on 404-page being opened inside child view -* (foxriver76) fixed issue if non-text default values are provided to a text jsonConfig component -* (foxriver76) implemented del key shortcut to delete a selected object + +- (foxriver76) show info if server time differs from client time +- (foxriver76) remove confusion with different names for state (datapoint and state) +- (jogibear9988) fixed link on 404-page being opened inside child view +- (foxriver76) fixed issue if non-text default values are provided to a text jsonConfig component +- (foxriver76) implemented del key shortcut to delete a selected object ## 6.9.1 (2023-08-22) -* (foxriver76) allow resizing of all columns in objects tab -* (foxriver76) without expert mode users are only allowed to edit objects in `0_userdata.0` and `alias.0` namespace -* (foxriver76) fixed keyboard navigation -* (foxriver76) fixed problem with showing controller upgrade instructions if no UI upgrade is supported + +- (foxriver76) allow resizing of all columns in objects tab +- (foxriver76) without expert mode users are only allowed to edit objects in `0_userdata.0` and `alias.0` namespace +- (foxriver76) fixed keyboard navigation +- (foxriver76) fixed problem with showing controller upgrade instructions if no UI upgrade is supported ## 6.9.0 (2023-08-21) -* (bluefox) Added possibility to change a log direction -* (bluefox) JSON config: Added possibility to filter out internal IP addresses -* (bluefox) JSON config: Added _changed flag for formula in JSON config -* (bluefox) JSON config: Added option `reloadBrowser` to sendto in JSON config -* (bluefox) JSON config: Allowed positioning of add button on the very top of the table -* (bluefox) JSON config: Trim strings by saving and not by typing -* (bluefox) Added alias creation from object browser -* (bluefox) Allowed changing the chart type -* (foxriver76) show a date picker when setting state (role: date/type: number) -* (foxriver76) fixed problem, that creation of folders was not possible -* (foxriver76) adapted a text to clarify, that only tarball can be installed from a path -* (foxriver76) type string/role date will now also be previewed as a date in objects tab -* (foxriver76) fixed problem with table formatting on history data point viewer -* (foxriver76) fixed problem that could render update dialog with invalid property -* (foxriver76) fixed sentry icon being in the wrong position if no compact flag is provided + +- (bluefox) Added possibility to change a log direction +- (bluefox) JSON config: Added possibility to filter out internal IP addresses +- (bluefox) JSON config: Added \_changed flag for formula in JSON config +- (bluefox) JSON config: Added option `reloadBrowser` to sendto in JSON config +- (bluefox) JSON config: Allowed positioning of add button on the very top of the table +- (bluefox) JSON config: Trim strings by saving and not by typing +- (bluefox) Added alias creation from object browser +- (bluefox) Allowed changing the chart type +- (foxriver76) show a date picker when setting state (role: date/type: number) +- (foxriver76) fixed problem, that creation of folders was not possible +- (foxriver76) adapted a text to clarify, that only tarball can be installed from a path +- (foxriver76) type string/role date will now also be previewed as a date in objects tab +- (foxriver76) fixed problem with table formatting on history data point viewer +- (foxriver76) fixed problem that could render update dialog with invalid property +- (foxriver76) fixed sentry icon being in the wrong position if no compact flag is provided ## 6.8.3 (2023-08-16) -* (foxriver76) added description to adapter rating dialog -* (bluefox) Extended the select component with grouping -* (bluefox) Allowed the sorting of adapters by name and not only by title -* (bluefox) Allowed the set state JSON config component + +- (foxriver76) added description to adapter rating dialog +- (bluefox) Extended the select component with grouping +- (bluefox) Allowed the sorting of adapters by name and not only by title +- (bluefox) Allowed the set state JSON config component ## 6.8.0 (2023-08-14) -* (foxriver76) try to find the correct IP for the controller UI multihost slave upgrade -* (foxriver76) admin is now showing update information, while it is stopped during upgrade -* (foxriver76) required Node.js version is 16 as 14 is End-Of-Life -* (foxriver76) fixed downloading folders recursive + +- (foxriver76) try to find the correct IP for the controller UI multihost slave upgrade +- (foxriver76) admin is now showing update information, while it is stopped during upgrade +- (foxriver76) required Node.js version is 16 as 14 is End-Of-Life +- (foxriver76) fixed downloading folders recursive ## 6.7.2 (2023-08-09) -* (foxriver76) remove https certificate options -* (foxriver76) prevent error log of not used certificates even-though they are used -* (foxriver76) fixed issue with docker host cards on intro tab -* (foxriver76) fixed issue if adapter readme is opened in new tab -* (bluefox) corrected opening of custom tabs, e.g., for fullcalendar -* (bluefox) allowed downloading of recursive folders + +- (foxriver76) remove https certificate options +- (foxriver76) prevent error log of not used certificates even-though they are used +- (foxriver76) fixed issue with docker host cards on intro tab +- (foxriver76) fixed issue if adapter readme is opened in new tab +- (bluefox) corrected opening of custom tabs, e.g., for fullcalendar +- (bluefox) allowed downloading of recursive folders ## 6.7.0 (2023-08-02) -* (foxriver76) display more specific information about docker installation on host card -* (foxriver76) allowed downloading folders in files tab + +- (foxriver76) display more specific information about docker installation on host card +- (foxriver76) allowed downloading folders in files tab ## 6.6.5 (2023-07-31) -* (foxriver76) also show js-controller upgrade instructions if UI upgrade is available -* (buefox/foxriver76) allow array values to be stored in custom editor -* (foxriver76) fixed bug which prevented the creation of new objects -* (bluefox/foxriver76) fixed bug which prevented opening adapter readme -* (foxriver76) fixed ChipInput jsonConfig component + +- (foxriver76) also show js-controller upgrade instructions if UI upgrade is available +- (buefox/foxriver76) allow array values to be stored in custom editor +- (foxriver76) fixed bug which prevented the creation of new objects +- (bluefox/foxriver76) fixed bug which prevented opening adapter readme +- (foxriver76) fixed ChipInput jsonConfig component ## 6.6.4 (2023-07-28) -* (bluefox) Better licenses handling (especially for vis-2) + +- (bluefox) Better licenses handling (especially for vis-2) ## 6.6.3 (2023-07-27) -* (foxriver76) fixed "Let's Encrypt" link not being clickable inside system settings -* (foxriver76) fixed false positives for "not much space left on device" warning -* (foxriver76) fixed issue with npm version determination on some installations -* (foxriver76) reset the logout timer UI if session is extended -* (rovo89) apply button color change of v6.6.1 for all buttons -* (foxriver76) correctly display materialized tabs when configured with io-package `adminUi` property -* (foxriver76) enable keyboard navigation for objects tab + +- (foxriver76) fixed "Let's Encrypt" link not being clickable inside system settings +- (foxriver76) fixed false positives for "not much space left on device" warning +- (foxriver76) fixed issue with npm version determination on some installations +- (foxriver76) reset the logout timer UI if session is extended +- (rovo89) apply button color change of v6.6.1 for all buttons +- (foxriver76) correctly display materialized tabs when configured with io-package `adminUi` property +- (foxriver76) enable keyboard navigation for objects tab ## 6.6.1 (2023-07-17) -* (foxriver76) Many GUI improvements -* (bluefox) New json config component added: license agreement -* (foxriver76) also show non-stable repo warning on the hosts tab -* (foxriver76) fixed jsonConfig slider with different max/min values than 0/100 -* (foxriver76) fixed jsonConfig number element arrows -* (foxriver76) fixed jsonConfig coordinates not triggering onChange and not being prefilled -* (foxriver76) fixed jsonConfig jsonEditor component -* (foxriver76) assume status as offline if status state value has been deleted (e.g., via `setState` with `expire` option) -* (foxriver76) fixed jsonConfig CheckLicense edge case error -* (foxriver76) added tooltip to ObjectBrowserValue to show that ack-flag cannot be used to control a device -* (foxriver76) fixed host name not being visible on some themes -* (foxriver76) fixed issue with jsonConfig CRON placeholder overlapping input -* (foxriver76) button color in non-expert mode will not be changed according to ack/q anymore -* (foxriver76) fixed multiple problems with jsonConfig coordinates when using `useSystemName` and separate `latitude`/`longitutde` states -* (foxriver76) when adding an icon to an object, to not show already uploaded non-existing image initially -* (foxriver76) when the session timer falls below the 2 - minute mark, show button to extend the session + +- (foxriver76) Many GUI improvements +- (bluefox) New json config component added: license agreement +- (foxriver76) also show non-stable repo warning on the hosts tab +- (foxriver76) fixed jsonConfig slider with different max/min values than 0/100 +- (foxriver76) fixed jsonConfig number element arrows +- (foxriver76) fixed jsonConfig coordinates not triggering onChange and not being prefilled +- (foxriver76) fixed jsonConfig jsonEditor component +- (foxriver76) assume status as offline if status state value has been deleted (e.g., via `setState` with `expire` option) +- (foxriver76) fixed jsonConfig CheckLicense edge case error +- (foxriver76) added tooltip to ObjectBrowserValue to show that ack-flag cannot be used to control a device +- (foxriver76) fixed host name not being visible on some themes +- (foxriver76) fixed issue with jsonConfig CRON placeholder overlapping input +- (foxriver76) button color in non-expert mode will not be changed according to ack/q anymore +- (foxriver76) fixed multiple problems with jsonConfig coordinates when using `useSystemName` and separate `latitude`/`longitutde` states +- (foxriver76) when adding an icon to an object, to not show already uploaded non-existing image initially +- (foxriver76) when the session timer falls below the 2 - minute mark, show button to extend the session ## 6.6.0 (2023-07-05) -* (klein0r) New json config component added: accordion -* (bluefox) Added site name and corrected the system dialog + +- (klein0r) New json config component added: accordion +- (bluefox) Added site name and corrected the system dialog ## 6.5.9 (2023-06-19) -* (bluefox) Added support for update of the js-controller slaves + +- (bluefox) Added support for update of the js-controller slaves ## 6.5.8 (2023-06-12) -* (foxriver76) The log size will be parsed correctly for controller v5 + +- (foxriver76) The log size will be parsed correctly for controller v5 ## 6.5.7 (2023-06-06) -* (bluefox) ZIP archives will be saved in files and not in states + +- (bluefox) ZIP archives will be saved in files and not in states ## 6.5.3 (2023-05-24) -* (bluefox) Added support for the js-controller update + +- (bluefox) Added support for the js-controller update ## 6.4.4 (2023-05-10) -* (bluefox) Added `imageSendTo` Control to JSONConfig -* (bluefox) Added possibility to filter objects in selectID JSON component + +- (bluefox) Added `imageSendTo` Control to JSONConfig +- (bluefox) Added possibility to filter objects in selectID JSON component ## 6.4.3 (2023-03-31) -* (bluefox) Corrected the folder rights edit dialog + +- (bluefox) Corrected the folder rights edit dialog ## 6.4.2 (2023-03-27) -* (bluefox) Better check of the certificates + +- (bluefox) Better check of the certificates ## 6.4.1 (2023-03-24) -* (bluefox) Fallback on normal https webserver in case of not let's encrypt certificates -* (bluefox) Show readme from GitHub + +- (bluefox) Fallback on normal https webserver in case of not let's encrypt certificates +- (bluefox) Show readme from GitHub ## 6.4.0 (2023-03-22) -* (bluefox) Breaking change: Configuration of Let's encrypt certificates moved to `iobroker.acme` adapter -* (bluefox) Added port controller to JSON config -* (bluefox) Added `certificates` to JSON config + +- (bluefox) Breaking change: Configuration of Let's encrypt certificates moved to `iobroker.acme` adapter +- (bluefox) Added port controller to JSON config +- (bluefox) Added `certificates` to JSON config ## 6.3.7 (2023-03-12) -* (bluefox) Better tooltips in object browser -* Added again possibility to hide/show of columns in object browser + +- (bluefox) Better tooltips in object browser +- Added again possibility to hide/show of columns in object browser ## 6.3.6 (2023-01-29) -* (bluefox) Allowed the edit of log level in the configuration tab + +- (bluefox) Allowed the edit of log level in the configuration tab ## 6.3.5 (2022-12-22) -* (bluefox) Corrected reading of node.js version + +- (bluefox) Corrected reading of node.js version ## 6.3.4 (2022-12-18) -* (bluefox) Corrected crashes in object browser + +- (bluefox) Corrected crashes in object browser ## 6.3.3 (2022-12-14) -* (bluefox) Corrected icons in object browser + +- (bluefox) Corrected icons in object browser ## 6.3.2 (2022-12-12) -* (bluefox) Added `useNative` option to `sendTo` JSON Config component -* (bluefox) Added `checkLicense` and `uuid` components to JSON Config -* (bluefox) Corrected the news handler + +- (bluefox) Added `useNative` option to `sendTo` JSON Config component +- (bluefox) Added `checkLicense` and `uuid` components to JSON Config +- (bluefox) Corrected the news handler ## 6.2.23 (2022-10-12) -* (Apollon77) Prepare for future js-controller versions -* (bluefox) Corrected deletion of objects + +- (Apollon77) Prepare for future js-controller versions +- (bluefox) Corrected deletion of objects ## 6.2.22 (2022-09-14) -* (bluefox) Corrected admin4 adapter settings + +- (bluefox) Corrected admin4 adapter settings ## 6.2.21 (2022-09-05) -* (bluefox) Corrected small JSON config issue + +- (bluefox) Corrected small JSON config issue ## 6.2.20 (2022-08-29) -* (bluefox) Corrected GUI issues + +- (bluefox) Corrected GUI issues ## 6.2.19 (2022-08-27) -* (bluefox) Corrected some issues + +- (bluefox) Corrected some issues ## 6.2.18 (2022-08-24) -* (bluefox) Corrected GUI bugs on custom settings + +- (bluefox) Corrected GUI bugs on custom settings ## 6.2.17 (2022-08-19) -* (bluefox) Corrected GUI bug on intro tab + +- (bluefox) Corrected GUI bug on intro tab ## 6.2.16 (2022-08-18) -* (bluefox) Corrected many GUI issues -* (bluefox) Added `stable` flag for repositories -* (bluefox) Added reset button for repositories -* (bluefox) Improved `writeFile` function for socket communication + +- (bluefox) Corrected many GUI issues +- (bluefox) Added `stable` flag for repositories +- (bluefox) Added reset button for repositories +- (bluefox) Improved `writeFile` function for socket communication ## 6.2.14 (2022-08-06) -* (Apollon77) Fix for OAuth2 authentication response success page + +- (Apollon77) Fix for OAuth2 authentication response success page ## 6.2.13 (2022-08-01) -* (bluefox) Corrected JSON config + +- (bluefox) Corrected JSON config ## 6.2.12 (2022-07-31) -* (bluefox) Corrected the Text input field in JSON configuration + +- (bluefox) Corrected the Text input field in JSON configuration ## 6.2.6 (2022-07-28) -* (bluefox) Implemented Oauth2 workflow for adapters -* (bluefox) Corrected encrypt/decrypt functions + +- (bluefox) Implemented Oauth2 workflow for adapters +- (bluefox) Corrected encrypt/decrypt functions ## 6.2.4 (2022-07-20) -* (bluefox) Corrected yahka settings + +- (bluefox) Corrected yahka settings ## 6.2.3 (2022-07-18) -* (AlCalzone) Implemented AES-192 encryption and decryption in GUI + +- (AlCalzone) Implemented AES-192 encryption and decryption in GUI ## 6.2.2 (2022-07-18) -* (bluefox) Corrected JSON config table and login page + +- (bluefox) Corrected JSON config table and login page ## 6.2.1 (2022-07-14) -* (bluefox) Release 6.2 + +- (bluefox) Release 6.2 ## 6.1.12 (2022-07-12) -* (bluefox) Fixed GUI issues -* (bluefox) Release candidate 2 + +- (bluefox) Fixed GUI issues +- (bluefox) Release candidate 2 ## 6.1.11 (2022-07-06) -* (bluefox) Fixed GUI issues -* (bluefox) Release candidate 1 + +- (bluefox) Fixed GUI issues +- (bluefox) Release candidate 1 ## 6.1.10 (2022-07-04) -* (bluefox) Fixed issue with map + +- (bluefox) Fixed issue with map ## 6.1.9 (2022-07-02) -* (bluefox) Some GUI fixes done + +- (bluefox) Some GUI fixes done ## 6.1.8 (2022-07-01) -* (bluefox) Corrected the host update instructions + +- (bluefox) Corrected the host update instructions ## 6.1.7 (2022-06-29) -* (bluefox) Some GUI fixes done + +- (bluefox) Some GUI fixes done ## 6.1.6 (2022-06-27) -* (bluefox) Some GUI fixes done + +- (bluefox) Some GUI fixes done ## 6.1.4 (2022-06-23) -* (bluefox) Added settings to define loading screen + +- (bluefox) Added settings to define loading screen ## 6.1.1 (2022-06-22) -* (bluefox) Corrected russian translations -* (bluefox) Preparations for iobroker cloud + +- (bluefox) Corrected russian translations +- (bluefox) Preparations for iobroker cloud ## 6.1.0 (2022-06-22) -* (bluefox) allowed to use admin behind reverse proxy -* (bluefox) Added new JsonConfig components: Slider, Room selector, Function selector + +- (bluefox) allowed to use admin behind reverse proxy +- (bluefox) Added new JsonConfig components: Slider, Room selector, Function selector ## 6.0.8 (2022-06-21) -* (bluefox) Added multiple choice by `selectSendTo` -* (bluefox) Added warning if some javascript not saved -* (bluefox) Some GUI fixes done + +- (bluefox) Added multiple choice by `selectSendTo` +- (bluefox) Added warning if some javascript not saved +- (bluefox) Some GUI fixes done ## 6.0.7 (2022-06-20) -* (bluefox) Many GUI fixes done + +- (bluefox) Many GUI fixes done ## 6.0.6 (2022-06-19) -* (bluefox) Added file selector with select dialog + +- (bluefox) Added file selector with select dialog ## 6.0.5 (2022-06-18) -* (bluefox) Added file selector for JSON-Config -* (bluefox) Added the experimental synchronize function (in expertMode) -* (bluefox) Many GUI fixes done + +- (bluefox) Added file selector for JSON-Config +- (bluefox) Added the experimental synchronize function (in expertMode) +- (bluefox) Many GUI fixes done ## 6.0.4 (2022-06-13) -* (bluefox) implemented the resize of columns in some tables + +- (bluefox) implemented the resize of columns in some tables ## 6.0.3 (2022-06-10) -* (bluefox) Many GUI fixes done + +- (bluefox) Many GUI fixes done ## 6.0.2 (2022-06-08) -* (bluefox) Many GUI fixes done + +- (bluefox) Many GUI fixes done ## 6.0.1 (2022-06-07) -* (bluefox) Many GUI fixes done + +- (bluefox) Many GUI fixes done ## 6.0.0 (2022-06-03) -* (bluefox) Breaking changes: no admin@v4(material) interface. Only react interface is possible. -* (bluefox) Breaking changes: older browsers do not supported anymore. -* (bluefox) Migration from material-ui to mui@v5 -* (bluefox) Many GUI fixes -* (bluefox) Support of JSON5 for the config and custom files -* (bluefox) Added run/stop buttons in instance settings dialog -* (bluefox) Added support for the file change events + +- (bluefox) Breaking changes: no admin@v4(material) interface. Only react interface is possible. +- (bluefox) Breaking changes: older browsers do not supported anymore. +- (bluefox) Migration from material-ui to mui@v5 +- (bluefox) Many GUI fixes +- (bluefox) Support of JSON5 for the config and custom files +- (bluefox) Added run/stop buttons in instance settings dialog +- (bluefox) Added support for the file change events ## 5.4.9 (2022-05-12) -* (bluefox) Corrected charts -* (bluefox) Corrected socket command getObjects + +- (bluefox) Corrected charts +- (bluefox) Corrected socket command getObjects ## 5.4.8 (2022-05-09) -* (bluefox) Corrected some errors in Object Browser + +- (bluefox) Corrected some errors in Object Browser ## 5.4.7 (2022-05-09) -* (bluefox) Reload GUI if a new admin version detected + +- (bluefox) Reload GUI if a new admin version detected ## 5.4.6 (2022-05-09) -* (bluefox) Corrected readLogs command -* (bluefox) Corrected file deletion + +- (bluefox) Corrected readLogs command +- (bluefox) Corrected file deletion ## 5.4.3 (2022-05-06) -* (bluefox) Used common sockets (could be buggy) -* (bluefox) Added chips to JSON config + +- (bluefox) Used common sockets (could be buggy) +- (bluefox) Added chips to JSON config ## 5.3.8 (2022-04-14) -* (Apollon77) Changed the datapoint history list -* (bluefox) Added support for swagger adapter + +- (Apollon77) Changed the datapoint history list +- (bluefox) Added support for swagger adapter ## 5.3.7 (2022-04-10) -* (bluefox) Changed the chart rendering + +- (bluefox) Changed the chart rendering ## 5.3.6 (2022-04-03) -* (bluefox) Corrected the host selector in "add instance" dialog -* (bluefox) corrected display of "null" values, e.g. by time/date + +- (bluefox) Corrected the host selector in "add instance" dialog +- (bluefox) corrected display of "null" values, e.g. by time/date ## 5.3.4 (2022-03-27) -* (Apollon77) Fix some crash cases reported by Sentry -* (bluefox) Corrected user tab + +- (Apollon77) Fix some crash cases reported by Sentry +- (bluefox) Corrected user tab ## 5.3.3 (2022-03-19) -* (bluefox) Implemented the object coloring depends on other states + +- (bluefox) Implemented the object coloring depends on other states ## 5.3.2 (2022-03-18) -* (xXBJXx) added Radio Buttons for value2table -* (bluefox) Corrected many GUI errors + +- (xXBJXx) added Radio Buttons for value2table +- (bluefox) Corrected many GUI errors ## 5.3.1 (2022-02-21) -* (bluefox) Support of IPv6 address by links (vis, material, end so on) -* (bluefox) Corrected errors in the base settings -* (bluefox) Corrected error with the pre-selected language in wizard + +- (bluefox) Support of IPv6 address by links (vis, material, end so on) +- (bluefox) Corrected errors in the base settings +- (bluefox) Corrected error with the pre-selected language in wizard ## 5.3.0 (2022-02-09) -* (jogibear9988) Enable http compression in webserver -* (bluefox) Removed deprecated package "request" -* (bluefox) Added JSONL option for base settings -* (bluefox) Added small improvements -* (bluefox) Added the file viewer for binary states + +- (jogibear9988) Enable http compression in webserver +- (bluefox) Removed deprecated package "request" +- (bluefox) Added JSONL option for base settings +- (bluefox) Added small improvements +- (bluefox) Added the file viewer for binary states ## 5.2.3 (2021-12-24) -* (bluefox) Fixed error in `AutocompleteSendTo` -* (bluefox) Fixed error in charts + +- (bluefox) Fixed error in `AutocompleteSendTo` +- (bluefox) Fixed error in charts ## 5.2.2 (2021-12-21) -* (bluefox) Changed the minimal required js-controller version to 3.3.22 -* (bluefox) Used web-socket library 8 (no node 10 support anymore) + +- (bluefox) Changed the minimal required js-controller version to 3.3.22 +- (bluefox) Used web-socket library 8 (no node 10 support anymore) ## 5.2.1 (2021-11-28) -* (bluefox) Allow in expert mode the creation of states and channels in mqtt branch + +- (bluefox) Allow in expert mode the creation of states and channels in mqtt branch ## 5.2.0 (2021-11-26) -* (Apollon77) Fix crash cases reported via sentry -* (bluefox) Added support for multi-repositories + +- (Apollon77) Fix crash cases reported via sentry +- (bluefox) Added support for multi-repositories ## 5.1.28 (2021-11-10) -* (bluefox) Fixed discovery function -* (bluefox) Fixed some GUI bugs + +- (bluefox) Fixed discovery function +- (bluefox) Fixed some GUI bugs ## 5.1.25 (2021-08-15) -* (bluefox) Corrected some errors reported via sentry and the GitHub issues + +- (bluefox) Corrected some errors reported via sentry and the GitHub issues ## 5.1.23 (2021-08-05) -* (bluefox) Corrected some errors reported via sentry + +- (bluefox) Corrected some errors reported via sentry ## 5.1.19 (2021-07-31) -* (bluefox) Corrected some GUI errors + +- (bluefox) Corrected some GUI errors ## 5.1.17 (2021-07-30) -* (bluefox) Corrected the error on the adapter's tab + +- (bluefox) Corrected the error on the adapter's tab ## 5.1.16 (2021-07-30) -* (bluefox) Make the appearance of buttons configurable + +- (bluefox) Make the appearance of buttons configurable ## 5.1.15 (2021-07-26) -* (bluefox) Replaced the formula icon in the edit aliases dialog -* (bluefox) Added the logic for checkbox in JsonConfig + +- (bluefox) Replaced the formula icon in the edit aliases dialog +- (bluefox) Added the logic for checkbox in JsonConfig ## 5.1.14 (2021-07-23) -* (bluefox) Corrected error with "Intro" page. Warning: All cards must be deactivated anew. + +- (bluefox) Corrected error with "Intro" page. Warning: All cards must be deactivated anew. ## 5.1.13 (2021-07-21) -* (bluefox) Improved json config + +- (bluefox) Improved json config ## 5.1.12 (2021-07-16) -* (bluefox) The charts were improved -* (bluefox) Corrected the error with the jump links if more than one web instance + +- (bluefox) The charts were improved +- (bluefox) Corrected the error with the jump links if more than one web instance ## 5.1.11 (2021-07-12) -* (bluefox) Changed the filter of objects + +- (bluefox) Changed the filter of objects ## 5.1.10 (2021-07-09) -* (bluefox) Corrected some GUI errors + +- (bluefox) Corrected some GUI errors ## 5.1.9 (2021-06-09) -* (bluefox) Corrected some GUI errors + +- (bluefox) Corrected some GUI errors ## 5.1.8 (2021-06-06) -* (bluefox) Improved the list of predefined icons + +- (bluefox) Improved the list of predefined icons ## 5.1.7 (2021-06-04) -* (bluefox) Added the possibility to clear the schedule + +- (bluefox) Added the possibility to clear the schedule ## 5.1.6 (2021-06-02) -* (bluefox) Improved the custom settings + +- (bluefox) Improved the custom settings ## 5.1.5 (2021-05-30) -* (bluefox) Fix edit of enumeration + +- (bluefox) Fix edit of enumeration ## 5.1.4 (2021-05-27) -* (bluefox) Corrected error in log + +- (bluefox) Corrected error in log ## 5.1.3 (2021-05-26) -* (bluefox) Improved the GUI for enumerations + +- (bluefox) Improved the GUI for enumerations ## 5.1.2 (2021-05-26) -* (bluefox) Admin5: Fixed logs by the changing of host + +- (bluefox) Admin5: Fixed logs by the changing of host ## 5.1.1 (2021-05-25) -* (bluefox) Admin5: Fixed the host selector -* (bluefox) Admin5: Implemented the colored logs + +- (bluefox) Admin5: Fixed the host selector +- (bluefox) Admin5: Implemented the colored logs ## 5.1.0 (2021-05-24) -* (bluefox) Admin5: Fixed update of objects -* (bluefox) Admin5: React UI is by default enabled + +- (bluefox) Admin5: Fixed update of objects +- (bluefox) Admin5: React UI is by default enabled ## 5.0.32 (2021-05-23) -* (bluefox) Admin5: Support of ANSI codes in log + +- (bluefox) Admin5: Support of ANSI codes in log ## 5.0.31 (2021-05-21) -* (bluefox) Admin5: Improved the enumerations + +- (bluefox) Admin5: Improved the enumerations ## 5.0.30 (2021-05-21) -* (bluefox) Admin5: Fixed update of objects + +- (bluefox) Admin5: Fixed update of objects ## 5.0.29 (2021-05-19) -* (bluefox) Admin5: Fixed reorder of the items in menu + +- (bluefox) Admin5: Fixed reorder of the items in menu ## 5.0.28 (2021-05-18) -* (bluefox) Admin5: GUI fixes + +- (bluefox) Admin5: GUI fixes ## 5.0.27 (2021-05-17) -* (bluefox) Admin5: GUI fixes + +- (bluefox) Admin5: GUI fixes ## 5.0.26 (2021-05-16) -* (bluefox) Admin5: GUI fixes + +- (bluefox) Admin5: GUI fixes ## 5.0.25 (2021-05-15) -* (bluefox) Admin5: GUI fixes + +- (bluefox) Admin5: GUI fixes ## 5.0.24 (2021-05-14) -* (bluefox) Admin5: GUI fixes + +- (bluefox) Admin5: GUI fixes ## 5.0.22 (2021-05-12) -* (bluefox) Admin5: Fixed some bugs + +- (bluefox) Admin5: Fixed some bugs ## 5.0.21 (2021-05-11) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.20 (2021-05-10) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.19 (2021-05-09) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.18 (2021-05-07) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.17 (2021-05-06) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.16 (2021-05-05) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.15 (2021-05-05) -* (bluefox) optimized the loading process + +- (bluefox) optimized the loading process ## 5.0.14 (2021-05-03) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.13 (2021-05-02) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.12 (2021-05-01) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.11 (2021-04-29) -* (bluefox) Admin5: users management implemented + +- (bluefox) Admin5: users management implemented ## 5.0.10 (2021-04-27) -* (bluefox) Admin5: Implemented the language filter and selector for rating with comments + +- (bluefox) Admin5: Implemented the language filter and selector for rating with comments ## 5.0.9 (2021-04-27) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.8 (2021-04-24) -* (bluefox) Admin5: Implemented rating with comments + +- (bluefox) Admin5: Implemented rating with comments ## 5.0.7 (2021-04-23) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.6 (2021-04-20) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.5 (2021-04-20) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.4 (2021-04-18) -* (bluefox) Admin5: Fixed many bugs + +- (bluefox) Admin5: Fixed many bugs ## 5.0.3 (2021-04-17) -* (bluefox) Admin5: Many new features implemented + +- (bluefox) Admin5: Many new features implemented ## 5.0.2 (2020-12-26) -* (bluefox) Merged the changes from admin4 + +- (bluefox) Merged the changes from admin4 ## 5.0.0 (2020-09_23) -* (bluefox) The tile view implemented for the file browser + +- (bluefox) The tile view implemented for the file browser ## 4.2.1 (2021-01-12) -* (Apollon77) Also allow pre-prelease versions for dependency checks + +- (Apollon77) Also allow pre-prelease versions for dependency checks ## 4.2.0 (2021-01-08) -* (bluefox) Support of new Let's Encrypt (only with js-controller 3.2.x) + +- (bluefox) Support of new Let's Encrypt (only with js-controller 3.2.x) ## 4.1.13 (2021-01-08) -* (bluefox) Support of new Let's Encrypt (only with js-controller 3.2.x) + +- (bluefox) Support of new Let's Encrypt (only with js-controller 3.2.x) ## 4.1.12 (2020-12-12) -* (bluefox) Corrected the error with empty names in enums + +- (bluefox) Corrected the error with empty names in enums ## 4.1.11 (2020-11-22) -* (theimo1221) Prevent Duplicate Event Handling on Dropdown Checkboxes -* (paul53) fixed Objects dialog + +- (theimo1221) Prevent Duplicate Event Handling on Dropdown Checkboxes +- (paul53) fixed Objects dialog ## 4.1.10 (2020-10-08) -* (bluefox) Corrected the icons of the custom tabs. + +- (bluefox) Corrected the icons of the custom tabs. ## 4.1.8 (2020-09-03) -* (bluefox) Fixed editing of the objects with % sign in the ID. + +- (bluefox) Fixed editing of the objects with % sign in the ID. ## 4.1.13 (2021-01-08) -* (bluefox) Support of new Let's Encrypt (only with js-controller 3.2.x) + +- (bluefox) Support of new Let's Encrypt (only with js-controller 3.2.x) ## 4.1.12 (2020-12-12) -* (bluefox) Corrected the error with empty names in enums + +- (bluefox) Corrected the error with empty names in enums ## 4.1.11 (2020-11-22) -* (theimo1221) Prevent Duplicate Event Handling on Dropdown Checkboxes -* (paul53) fixed Objects dialog + +- (theimo1221) Prevent Duplicate Event Handling on Dropdown Checkboxes +- (paul53) fixed Objects dialog ## 4.1.10 (2020-10-08) -* (bluefox) Corrected the icons of the custom tabs. + +- (bluefox) Corrected the icons of the custom tabs. ## 4.1.8 (2020-09-03) -* (bluefox) Fixed editing of the objects with % sign in the ID. + +- (bluefox) Fixed editing of the objects with % sign in the ID. ## 4.1.6 (2020-07-26) -* (Apollon77) Increased the socket ping Interval and Timeout to maybe prevent the too fast reconnect attempts. + +- (Apollon77) Increased the socket ping Interval and Timeout to maybe prevent the too fast reconnect attempts. ## 4.1.5 (2020-07-26) -* (ldittmar) Add option to check for active/inactive instances and uuid-hash -* (Apollon77) prevent Sentry crash IOBROKER-ADMIN-Z + +- (ldittmar) Add option to check for active/inactive instances and uuid-hash +- (Apollon77) prevent Sentry crash IOBROKER-ADMIN-Z ## 4.1.3 (2020-07-25) -* (bluefox) Added binary state read and write -* (bluefox) small fixes + +- (bluefox) Added binary state read and write +- (bluefox) small fixes ## 4.1.1 (2020-04-25) -* (bluefox) Started the development of GUI based on React (only for developers) + +- (bluefox) Started the development of GUI based on React (only for developers) ## 4.0.10 (2020-05-14) -* (bluefox/Apollon77) Caught the web server errors -* (Apollon77) Prepare for js-controller 3.0 release + +- (bluefox/Apollon77) Caught the web server errors +- (Apollon77) Prepare for js-controller 3.0 release ## 4.0.9 (2020-04-19) -* (Apollon77) Fix password encryption logics and make compatible to js-controller 3.x again + +- (Apollon77) Fix password encryption logics and make compatible to js-controller 3.x again ## 4.0.8 (2020-04-18) -* (bluefox) The attempt to process error by the gz log show. -* (bluefox) Implement new automatic encryption/decryption for js-controller 3.0 -* (bluefox) add Sentry for error reporting with js-controller 3.0 + +- (bluefox) The attempt to process error by the gz log show. +- (bluefox) Implement new automatic encryption/decryption for js-controller 3.0 +- (bluefox) add Sentry for error reporting with js-controller 3.0 ## 4.0.5 (2020-02-23) -* (Apollon77) Workaround for socket.io bug #3555 added to make sure always the correct client files are delivered -* (Apollon77) remove socket.io-client dep again because we lookup via socket.io lib -* (klein0r) Added a warning message to Custom/GitHub installs (thanky @ldittmar81 for translations) + +- (Apollon77) Workaround for socket.io bug #3555 added to make sure always the correct client files are delivered +- (Apollon77) remove socket.io-client dep again because we lookup via socket.io lib +- (klein0r) Added a warning message to Custom/GitHub installs (thanky @ldittmar81 for translations) ## 4.0.4 (2020-02-19) -* (Apollon77) Fix socket.io-client dependency + +- (Apollon77) Fix socket.io-client dependency ## 4.0.3 (2020-02-19) -* (bluefox) Encrypted configuration was corrected. + +- (bluefox) Encrypted configuration was corrected. ## 4.0.2 (2020-02-12) -* (Apollon77) Downgrade semver to 6.3 to stay compatible with nodejs 8 + +- (Apollon77) Downgrade semver to 6.3 to stay compatible with nodejs 8 ## 4.0.1 (2020-02-07) -* (bluefox) Fixed the loading of some adapter configurations + +- (bluefox) Fixed the loading of some adapter configurations ## 4.0.0 (2020-01-15) -* (Apollon77) upgrade all dependencies, especially socketio to current version! This might break ipad 1/2 devices + +- (Apollon77) upgrade all dependencies, especially socketio to current version! This might break ipad 1/2 devices ### 3.7.9 (2020-01-28) -* (bluefox) The log downloading was fixed + +- (bluefox) The log downloading was fixed ### 3.7.8 (2020-01-26) -* (bluefox) The disabling of custom settings was corrected + +- (bluefox) The disabling of custom settings was corrected ### 3.7.5 (2019-12-29) -* (bluefox) Added the filter of the running instances -* (bluefox) The incompatible adapters will be hidden + +- (bluefox) Added the filter of the running instances +- (bluefox) The incompatible adapters will be hidden ### 3.7.1 (2019-11-20) -* (bluefox) Easy admin configuration was implemented + +- (bluefox) Easy admin configuration was implemented ### 3.6.12 (2019-11-04) -* (ldittmar) Add repo check to popup messages -* (ldittmar) Update Controller-Update info page -* (Apollon77) update deps + +- (ldittmar) Add repo check to popup messages +- (ldittmar) Update Controller-Update info page +- (Apollon77) update deps ### 3.6.11 (2019-10-16) -* (bluefox) Fixed login of non-admin user + +- (bluefox) Fixed login of non-admin user ### 3.6.10 (2019-10-11) -* (ldittmar) Add NPM version and OS check to popup messages -* (bluefox) Log paths were sanitized -* (bluefox) NPM packages were updated + +- (ldittmar) Add NPM version and OS check to popup messages +- (bluefox) Log paths were sanitized +- (bluefox) NPM packages were updated ### 3.6.7 (2019-09-24) -* (ldittmar) Add Node.JS version check to popup messages + +- (ldittmar) Add Node.JS version check to popup messages ### 3.6.6 (2019-09-18) -* (SchumyHao) Update Chinese translation -* (tmikulski) Update translations.json + +- (SchumyHao) Update Chinese translation +- (tmikulski) Update translations.json ### 3.6.5 (2019-09-02) -* (ldittmar) Fix anoying popups from info adapter + +- (ldittmar) Fix anoying popups from info adapter ### 3.6.4 (2019-06-03) -* (bluefox) Update nodejs recommendation message and check to recommend nodejs 10 + +- (bluefox) Update nodejs recommendation message and check to recommend nodejs 10 ### 3.6.3 (2019-06-02) -* (bluefox) Added deleteFile internal function (required for lovelace) -* (bluefox) Added yaml editor (required for lovelace) -* (bluefox) try to fix auto-fill option -* (dobis) Update italian translations + +- (bluefox) Added deleteFile internal function (required for lovelace) +- (bluefox) Added yaml editor (required for lovelace) +- (bluefox) try to fix auto-fill option +- (dobis) Update italian translations ### 3.6.2 (2019-05-05) -* (bluefox) Added onSave handler for custom dialogs + +- (bluefox) Added onSave handler for custom dialogs ### 3.6.1 (2019-04-18) -* (ldittmar) Better integration for ioBroker.info (1.3.7) -* (ldittmar) Update Gulp to v4 -* (ldittmar) Update materialize-css to v 1.0.0 + +- (ldittmar) Better integration for ioBroker.info (1.3.7) +- (ldittmar) Update Gulp to v4 +- (ldittmar) Update materialize-css to v 1.0.0 ### 3.6.0 (2018-11-08) -* (foxriver76) New update states added in info channel -* (foxriver76) Take respect to async when creating info states -* (SchumyHao) Added chinese translations + +- (foxriver76) New update states added in info channel +- (foxriver76) Take respect to async when creating info states +- (SchumyHao) Added chinese translations ### 3.5.10 (2018-09-22) -* (bluefox) Disable too many debug outputs + +- (bluefox) Disable too many debug outputs ### 3.5.9 (2018-09-12) -* (bluefox) The log output problem was fixed + +- (bluefox) The log output problem was fixed ### 3.5.8 (2018-09-03) -* (bluefox) Google map was replaces with "open street map" + +- (bluefox) Google map was replaces with "open street map" ### 3.5.7 (2018-08-30) -* (bluefox) Edit of the table entries in configuration dialog was corrected. + +- (bluefox) Edit of the table entries in configuration dialog was corrected. ### 3.5.6 (2018-08-22) -* (bluefox) Import and export of the instance configuration was implemented. + +- (bluefox) Import and export of the instance configuration was implemented. ### 3.5.5 (2018-08-21) -* (bluefox) Fix upload of files + +- (bluefox) Fix upload of files ### 3.5.3 (2018-08-18) -* (bluefox) Dropdown was fixed on touch devices -* (bluefox) Speedup build of instances + +- (bluefox) Dropdown was fixed on touch devices +- (bluefox) Speedup build of instances ### 3.5.1 (2018-08-11) -* (bluefox) Error in custom settings was fixed + +- (bluefox) Error in custom settings was fixed ### 3.5.0 (2018-08-03) -* (bluefox) Editing of enums was changed -* (bluefox) Logo was updated -* (bluefox) The function icons were added + +- (bluefox) Editing of enums was changed +- (bluefox) Logo was updated +- (bluefox) The function icons were added ### 3.4.9 (2018-07-17) -* (bluefox) Support of the custom login screen background -* (bluefox) show tooltip about refresh on instances page -* (bluefox) Destroy tabs after they left + +- (bluefox) Support of the custom login screen background +- (bluefox) show tooltip about refresh on instances page +- (bluefox) Destroy tabs after they left ### 3.4.8 (2018-07-17) -* (bluefox) fixed error with add new enum -* (bluefox) try to fix error with custom settings -* (bluefox) place all titles at the top in the config -* (bluefox) add expert mode to common -* (bluefox) allow edit of enum's names in many languages + +- (bluefox) fixed error with add new enum +- (bluefox) try to fix error with custom settings +- (bluefox) place all titles at the top in the config +- (bluefox) add expert mode to common +- (bluefox) allow edit of enum's names in many languages ### 3.4.7 (2018-06-25) -* (bluefox) add getInterfaces function -* (bluefox) save scroll position for some tables -* (bluefox) add info about "filtered out" + +- (bluefox) add getInterfaces function +- (bluefox) save scroll position for some tables +- (bluefox) add info about "filtered out" ### 3.4.6 (2018-06-18) -* (bluefox) Minor GUI fixes + +- (bluefox) Minor GUI fixes ### 3.4.5 (2018-06-12) -* (bluefox) Minor GUI fixes + +- (bluefox) Minor GUI fixes ### 3.4.4 (2018-06-04) -* (bluefox) add touch support for draggable and droppable -* (bluefox) edit raw value and not escaped in selectID.js -* (bluefox) allow edit of empty names in selectID.less -* (bluefox) add change with ack=true to selectID -* (bluefox) fixed select for admin3 in configuration dialog -* (bluefox) add autocomplete for configs -* (bluefox) fixed enums + +- (bluefox) add touch support for draggable and droppable +- (bluefox) edit raw value and not escaped in selectID.js +- (bluefox) allow edit of empty names in selectID.less +- (bluefox) add change with ack=true to selectID +- (bluefox) fixed select for admin3 in configuration dialog +- (bluefox) add autocomplete for configs +- (bluefox) fixed enums ### 3.4.3 (2018-05-13) -* (bluefox) The button in selectID was fixed -* (bluefox) disk info was added -* (bluefox) The filter in table mode on adapter tab was showed -* (bluefox) memAvailable for RAM monitoring is used -* (bluefox) fixed select problem in config dialog -* (bluefox) added the asking about unsaved scripts + +- (bluefox) The button in selectID was fixed +- (bluefox) disk info was added +- (bluefox) The filter in table mode on adapter tab was showed +- (bluefox) memAvailable for RAM monitoring is used +- (bluefox) fixed select problem in config dialog +- (bluefox) added the asking about unsaved scripts ### 3.4.2 (2018-05-04) -* (BuZZy1337) fixed wrong height calculation in select id dialog + +- (BuZZy1337) fixed wrong height calculation in select id dialog ### 3.4.1 (2018-05-03) -* (bluefox) fixed wait popup -* (bluefox) fixed button name in config dialog -* (BuZZy1337) escape html from log entries -* (bluefox) fixed objects counter -* (BuZZy1337) show current Tab in Page-Title -* (BuZZy1337) escape HTML Tags from selectID.js -* (bluefox) GUI bugfixes -* (BuZZy1337) Fix: Unable to scroll trough Dropdown on Touchscreens -* (BuZZy1337) Enhancement: Show current Tab in Pagetitle + +- (bluefox) fixed wait popup +- (bluefox) fixed button name in config dialog +- (BuZZy1337) escape html from log entries +- (bluefox) fixed objects counter +- (BuZZy1337) show current Tab in Page-Title +- (BuZZy1337) escape HTML Tags from selectID.js +- (bluefox) GUI bugfixes +- (BuZZy1337) Fix: Unable to scroll trough Dropdown on Touchscreens +- (BuZZy1337) Enhancement: Show current Tab in Pagetitle ### 3.4.0 (2018-04-23) -* (bluefox) show error about not activated admin for cloud -* (bluefox) handle mutlilanguage names -* (bluefox) show number of objects -* (BuZZy1337) always addChips when input blurs -* (bluefox) fixed select ID dialog for old styles -* (bluefox) add states view for object tab + +- (bluefox) show error about not activated admin for cloud +- (bluefox) handle mutlilanguage names +- (bluefox) show number of objects +- (BuZZy1337) always addChips when input blurs +- (bluefox) fixed select ID dialog for old styles +- (bluefox) add states view for object tab ### 3.3.9 (2018-04-12) -* (bluefox) The user and groups deletion was corrected -* (bluefox) Force using of socket.io 2.1.0 + +- (bluefox) The user and groups deletion was corrected +- (bluefox) Force using of socket.io 2.1.0 ### 3.3.8 (2018-04-10) -* (bluefox) Hosts selection is improved + +- (bluefox) Hosts selection is improved ### 3.3.7 (2018-04-10) -* (bluefox) small UI corrections + +- (bluefox) small UI corrections ### 3.3.5 (2018-03-25) -* (bondrogeen) info for server redesigned -* (bondrogeen) hosts list redesigned -* (bluefox) small UI corrections + +- (bondrogeen) info for server redesigned +- (bondrogeen) hosts list redesigned +- (bluefox) small UI corrections ### 3.3.4 (2018-03-17) -* (bluefox) small UI corrections + +- (bluefox) small UI corrections ### 3.3.3 (2018-03-15) -* (bluefox) small UI corrections + +- (bluefox) small UI corrections ### 3.3.1 (2018-03-11) -* (bluefox) Corrections for scenes -* (bluefox) move from socket.io 2.0.4 to 1.5.1 because of bug -* (bluefox) small fix for hosts + +- (bluefox) Corrections for scenes +- (bluefox) move from socket.io 2.0.4 to 1.5.1 because of bug +- (bluefox) small fix for hosts ### 3.3.0 (2018-03-10) -* (bluefox) Overview page was added -* (bluefox) Many bugs were fixed + +- (bluefox) Overview page was added +- (bluefox) Many bugs were fixed ### 3.2.4 (2018-03-04) -* (bluefox) Adjust layout on mobile devices + +- (bluefox) Adjust layout on mobile devices ### 3.2.1 (2018-03-03) -* (bluefox) Many UI fixes + +- (bluefox) Many UI fixes ### 3.2.0 (2018-02-09) -* (bluefox) The select ID dialog was fixed + +- (bluefox) The select ID dialog was fixed ### 3.1.12 (2018-02-05) -* (bondrogeen) Configuration dialog updated -* (bondrogeen) Open menu button is fixed + +- (bondrogeen) Configuration dialog updated +- (bondrogeen) Open menu button is fixed ### 3.1.11 (2018-02-04) -* (bluefox) Connection LED fixed + +- (bluefox) Connection LED fixed ### 3.1.10 (2018-02-02) -* (bluefox) update material CSS -* (bluefox) fixed permission error -* (bluefox) fixed filter of adapters + +- (bluefox) update material CSS +- (bluefox) fixed permission error +- (bluefox) fixed filter of adapters ### 3.1.7 (2018-01-31) -* (bluefox) Fixing the role selection -* (bluefox) It runs even in IE10 + +- (bluefox) Fixing the role selection +- (bluefox) It runs even in IE10 ### 3.1.6 (2018-01-30) -* (bluefox) Fixes for Firefox and MS-EDGE + +- (bluefox) Fixes for Firefox and MS-EDGE ### 3.1.2 (2018-01-25) -* (bluefox) GUI corrections + +- (bluefox) GUI corrections ### 3.0.12 (2018-01-19) -* (bluefox) Old configuration dialogs fixed -* (bluefox) convert strings to booleans by object edit -* (DeepCoreSystem) Updates in english, german and french translations -* (bluefox) buttons layout fixed -* (bluefox) event fixes + +- (bluefox) Old configuration dialogs fixed +- (bluefox) convert strings to booleans by object edit +- (DeepCoreSystem) Updates in english, german and french translations +- (bluefox) buttons layout fixed +- (bluefox) event fixes ### 3.0.11 (2018-01-11) -* (DeepCoreSystem) French update -* (bluefox) fixed error with empty ID -* (bluefox) add sort by "recently updated" -* (ldittmar) add readme and issues viewer + +- (DeepCoreSystem) French update +- (bluefox) fixed error with empty ID +- (bluefox) add sort by "recently updated" +- (ldittmar) add readme and issues viewer ### 3.0.10 (2018-01-06) -* (bluefox) Update indication -* (ldittmar) Use jQuery3 -* (AlCalzone) German translations + +- (bluefox) Update indication +- (ldittmar) Use jQuery3 +- (AlCalzone) German translations ### 3.0.7 (2018-01-01) -* (soef) update instances, objects and other lists -* (bluefox) rewrite interface with materialize + +- (soef) update instances, objects and other lists +- (bluefox) rewrite interface with materialize ### 2.0.11 (2017-10-23) -* (bluefox) Configurable event update disable threshold + +- (bluefox) Configurable event update disable threshold ### 2.0.10 (2017-10-22) -* (soef) added use of delete-key in the objects view + +- (soef) added use of delete-key in the objects view ### 2.0.8 (2017-10-12) -* (soef) fixed quickEdit: number with boolean value + +- (soef) fixed quickEdit: number with boolean value ### 2.0.7 (2017-10-11) -* (soef) Sort option added to object view + +- (soef) Sort option added to object view ### 2.0.5 (2017-10-06) -* (bluefox) Show the history charts if the web server has the https option on too + +- (bluefox) Show the history charts if the web server has the https option on too ### 2.0.3 (2017-08-13) -* (bluefox) Fix user access rights for sendToHost + +- (bluefox) Fix user access rights for sendToHost ### 2.0.2 (2017-08-12) -* (bluefox) Add the editing of the default access rights + +- (bluefox) Add the editing of the default access rights ### 2.0.1 (2017-08-07) -* (bluefox) Allow access via iobroker.pro -* (bluefox) Add node.js version recommendation + +- (bluefox) Allow access via iobroker.pro +- (bluefox) Add node.js version recommendation ### 1.8.3 (2017-07-24) -* (bluefox) allow access on tmp directory + +- (bluefox) allow access on tmp directory ### 1.8.0 (2017-06-02) -* (bluefox) split into modules + +- (bluefox) split into modules ### 1.7.6 (2017-06-01) -* (bluefox) Fix edit of the enum name + +- (bluefox) Fix edit of the enum name ### 1.7.5 (2017-05-20) -* (bluefox) catch error if translated object is not text -* (bluefox) update selectID.js -* (bluefox) do not open configuration dialog for instances with no config -* (Steiger04) select multiple auch bei data-name="[eigner-name]" + +- (bluefox) catch error if translated object is not text +- (bluefox) update selectID.js +- (bluefox) do not open configuration dialog for instances with no config +- (Steiger04) select multiple auch bei data-name="[eigner-name]" ### 1.7.3 (2017-03-25) -* (bluefox) fixed license dialog -* (bluefox) change color of tooltip text -* (ykuendig) update german translation -* (bluefox) add docs + +- (bluefox) fixed license dialog +- (bluefox) change color of tooltip text +- (ykuendig) update german translation +- (bluefox) add docs ### 1.7.2 (2017-03-15) -* (bluefox) add statistics selector for no-city -* (bluefox) support of discovery by first start + +- (bluefox) add statistics selector for no-city +- (bluefox) support of discovery by first start ### 1.7.1 (2017-03-11) -* (apollon77) fixed save button functionality -* (ykuendig) Update german translations -* (bluefox) patch repositories to support stable + +- (apollon77) fixed save button functionality +- (ykuendig) Update german translations +- (bluefox) patch repositories to support stable ### 1.7.0 (2017-03-08) -* (bluefox) fixed log -* (bluefox) show jQuery button for role button -* (apollon77) update testing setup.js -* (bluefox) fixed wetty loading -* (bluefox) fixed add/delete tabs -* (bluefox) implement hints for configuration dialog -* (bluefox) redirect if IP address changes -* (bluefox) add tooltip instruction -* (bluefox) wizard support -* (bluefox) fixed acl error -* (bluefox) fixed license agree button + +- (bluefox) fixed log +- (bluefox) show jQuery button for role button +- (apollon77) update testing setup.js +- (bluefox) fixed wetty loading +- (bluefox) fixed add/delete tabs +- (bluefox) implement hints for configuration dialog +- (bluefox) redirect if IP address changes +- (bluefox) add tooltip instruction +- (bluefox) wizard support +- (bluefox) fixed acl error +- (bluefox) fixed license agree button ### 1.6.12 (2017-01-31) -* (bluefox) Show message rates for adapters + +- (bluefox) Show message rates for adapters ### 1.6.11 (2017-01-21) -* (bluefox) Support of web extensions -* (bluefox) Fix error in expert mode on adapter tab + +- (bluefox) Support of web extensions +- (bluefox) Fix error in expert mode on adapter tab ### 1.6.9 (2016-12-19) -* (bluefox) Fix problem with the enums editing + +- (bluefox) Fix problem with the enums editing ### 1.6.8 (2016-11-26) -* (bluefox) Fix problem with install of instances + +- (bluefox) Fix problem with install of instances ### 1.6.7 (2016-11-12) -* (bluefox) expert mode in adapters: allow install of js-controller from git, allow install specific adapter version -* (bluefox) fixed confirm dialog + +- (bluefox) expert mode in adapters: allow install of js-controller from git, allow install specific adapter version +- (bluefox) fixed confirm dialog ### 1.6.6 (2016-11-06) -* (bluefox) update jQuery UI version -* (bluefox) show update hint for controller + +- (bluefox) update jQuery UI version +- (bluefox) show update hint for controller ### 1.6.5 (2016-10-31) -* (bluefox) update selectID.js -* (bluefox) better log messages in GUI -* (bluefox) remove js-controller from github install + +- (bluefox) update selectID.js +- (bluefox) better log messages in GUI +- (bluefox) remove js-controller from github install ### 1.6.4 (2016-10-14) -* (bluefox) Changes for JS adapter + +- (bluefox) Changes for JS adapter ### 1.6.3 (2016-09-21) -* (bluefox) fixed upload of custom installations + +- (bluefox) fixed upload of custom installations ### 1.6.2 (2016-09-12) -* (bluefox) fixed hosts leds -* (bluefox) fixed error in system settings -* (bluefox) small fixes -* (bluefox) add "upgrade all" button (experimental) + +- (bluefox) fixed hosts leds +- (bluefox) fixed error in system settings +- (bluefox) small fixes +- (bluefox) add "upgrade all" button (experimental) ### 1.6.1 (2016-09-03) -* (bluefox) change hosts tab + +- (bluefox) change hosts tab ### 1.6.0 (2016-08-30) -* (bluefox) new letsencrypt concept + +- (bluefox) new letsencrypt concept ### 1.5.3 (2016-08-27) -* (bluefox) Debug outputs for letsencrypt + +- (bluefox) Debug outputs for letsencrypt ### 1.5.2 (2016-08-27) -* (bluefox) used pure letsencrypt module + +- (bluefox) used pure letsencrypt module ### 1.5.1 (2016-08-22) -* (bluefox) fixed error in instances table + +- (bluefox) fixed error in instances table ### 1.5.0 (2016-08-19) -* (bluefox) added support of Let's Encrypt + +- (bluefox) added support of Let's Encrypt ### 1.4.1 (2016-07-30) -* (bluefox) support of multiple WEB instances -* (bluefox) fixed weekdays for cron + +- (bluefox) support of multiple WEB instances +- (bluefox) fixed weekdays for cron ### 1.4.0 (2016-07-27) -* (bluefox) implement settings for autorestart -* (bluefox) do not allow editing group instances for javascript + +- (bluefox) implement settings for autorestart +- (bluefox) do not allow editing group instances for javascript ### 1.3.0 (2016-07-18) -* (bluefox) fixed error with early logout -* (bluefox) update passport.socketio -* (bluefox) disable update button if version is incompatible + +- (bluefox) fixed error with early logout +- (bluefox) update passport.socketio +- (bluefox) disable update button if version is incompatible ### 1.2.7 (2016-07-11) -* (bluefox) support of chained certificates as drag&drop + +- (bluefox) support of chained certificates as drag&drop ### 1.2.6 (2016-07-06) -* (bluefox) support of chained certificates + +- (bluefox) support of chained certificates ### 1.2.5 (2016-07-05) -* (bluefox) install from github + +- (bluefox) install from github ### 1.2.4 (2016-06-25) -* (bluefox) change color of log entries -* (bluefox) add icon to logout button -* (bluefox) hide reload by WWW only adapters + +- (bluefox) change color of log entries +- (bluefox) add icon to logout button +- (bluefox) hide reload by WWW only adapters ### 1.2.3 (2016-06-05) -* (bluefox) fixed memory displaying + +- (bluefox) fixed memory displaying ### 1.2.2 (2016-05-31) -* (bluefox) fixed memory displaying if adapter does not run + +- (bluefox) fixed memory displaying if adapter does not run ### 1.2.1 (2016-05-28) -* (bluefox) highlight changes of states -* (bluefox) show number of processes and free memory in % + +- (bluefox) highlight changes of states +- (bluefox) show number of processes and free memory in % ### 1.2.0 (2016-05-28) -* (bluefox) show RAM utilization -* (bluefox) show change log in admin tab + +- (bluefox) show RAM utilization +- (bluefox) show change log in admin tab ### 1.1.1 (2016-05-17) -* (bluefox) fixed set of states in States-Tab -* (bluefox) show history data from adapter and not from updates -* (bluefox) change default chart to flot -* (bluefox) fixed error if host has no IP address -* (bluefox) show on the bottom only adapters without config and without links -* (bluefox) fixed filter in adapters if upper case -* (bluefox) change file open from selectID Dialog + +- (bluefox) fixed set of states in States-Tab +- (bluefox) show history data from adapter and not from updates +- (bluefox) change default chart to flot +- (bluefox) fixed error if host has no IP address +- (bluefox) show on the bottom only adapters without config and without links +- (bluefox) fixed filter in adapters if upper case +- (bluefox) change file open from selectID Dialog ### 1.1.0 (2016-04-30) -* (bluefox) change seconds to milliseconds by ts and lc + +- (bluefox) change seconds to milliseconds by ts and lc ### 1.0.3 (2016-04-30) -* (bluefox) fixed write of state in the objects tab + +- (bluefox) fixed write of state in the objects tab ### 1.0.2 (2016-04-07) -* (bluefox) show npm errors of version + +- (bluefox) show npm errors of version ### 1.0.1 (2016-03-22) -* (bluefox) show web link button + +- (bluefox) show web link button ### 1.0.0 (2016-03-15) -* (bluefox) adapter is good enough to be released -* (bluefox) fixed LEDs -* (bluefox) disable double-click in Objects + +- (bluefox) adapter is good enough to be released +- (bluefox) fixed LEDs +- (bluefox) disable double-click in Objects ### 0.8.7 (2016-03-15) -* (bluefox) fixed LED status + +- (bluefox) fixed LED status ### 0.8.6 (2016-03-10) -* (bluefox) show quality + +- (bluefox) show quality ### 0.8.5 (2016-03-09) -* (bluefox) return javascript.x to non-experts view -* (bluefox) show quality of states -* (bluefox) hide experts tabs by new installations -* (installator / vtec83) russian translations + +- (bluefox) return javascript.x to non-experts view +- (bluefox) show quality of states +- (bluefox) hide experts tabs by new installations +- (installator / vtec83) russian translations ### 0.8.4 (2016-03-08) -* (bluefox) remove script.js.* from non-expert-view -* (bluefox) fixed selectId for javascript tab + +- (bluefox) remove script.js.\* from non-expert-view +- (bluefox) fixed selectId for javascript tab ### 0.8.3 (2016-02-29) -* (bluefox) fixed delete of objects tree + +- (bluefox) fixed delete of objects tree ### 0.8.2 (2016-02-29) -* (bluefox) disable start button if in process + +- (bluefox) disable start button if in process ### 0.8.1 (2016-02-27) -* (bluefox) expert mode -* (bluefox) new instances page -* (bluefox) edit objects directly on the page and not in the dialog + +- (bluefox) expert mode +- (bluefox) new instances page +- (bluefox) edit objects directly on the page and not in the dialog ### 0.8.0 (2016-02-18) -* (bluefox) move enums into own file -* (bluefox) modify selectID.js to support new javascript layout -* (bluefox) add new variables: admin.x.info.updatesNumber and admin.x.info.updatesList to show available updates + +- (bluefox) move enums into own file +- (bluefox) modify selectID.js to support new javascript layout +- (bluefox) add new variables: admin.x.info.updatesNumber and admin.x.info.updatesList to show available updates ### 0.7.5 (2016-02-11) -* (bluefox) support of text2command -* (bluefox) support of noConfig flag -* (bluefox) fixed tabs -* (bluefox) add support of adminTab.ignoreConfigUpdate + +- (bluefox) support of text2command +- (bluefox) support of noConfig flag +- (bluefox) fixed tabs +- (bluefox) add support of adminTab.ignoreConfigUpdate ### 0.7.4 (2016-01-28) -* (bluefox) pause button for logs and events + +- (bluefox) pause button for logs and events ### 0.7.3 (2016-01-21) -* (bluefox) fixed groups dialog -* (bluefox) allow set max memory limit for adapters + +- (bluefox) fixed groups dialog +- (bluefox) allow set max memory limit for adapters ### 0.7.2 (2015-12-18) -* (bluefox) translate "clear"-event button + +- (bluefox) translate "clear"-event button ### 0.7.1 (2015-12-14) -* (husky-koglhof) added support for up-/download of objecttrees -* (bluefox) disable chart if dialog closed. -* (bluefox) store selected history type in history dialog -* (bluefox) fixed selectId dialog -* (bluefox) fixed graph -* (bluefox) add title to index.html -* (bluefox) change theme -* (bluefox) fixed buttons + +- (husky-koglhof) added support for up-/download of objecttrees +- (bluefox) disable chart if dialog closed. +- (bluefox) store selected history type in history dialog +- (bluefox) fixed selectId dialog +- (bluefox) fixed graph +- (bluefox) add title to index.html +- (bluefox) change theme +- (bluefox) fixed buttons ### 0.7.0 (2015-11-15) -* (bluefox) support of multi history + +- (bluefox) support of multi history ### 0.6.6 (2015-11-02) -* (bluefox) add support of certificates (-----BEGIN PRIVATE KEY-----) + +- (bluefox) add support of certificates (-----BEGIN PRIVATE KEY-----) ### 0.6.5 (2015-10-31) -* (bluefox) maginfy icon by mouseover + +- (bluefox) maginfy icon by mouseover ### 0.6.4 (2015-10-27) -* (bluefox) fixed write of enums -* (bluefox) fixed buttons in instance tab + +- (bluefox) fixed write of enums +- (bluefox) fixed buttons in instance tab ### 0.6.3 (2015-10-22) -* (bluefox) fixed delete of adapter + +- (bluefox) fixed delete of adapter ### 0.6.2 (2015-10-18) -* (bluefox) add confirmation by instance deletion + +- (bluefox) add confirmation by instance deletion ### 0.6.1 (2015-10-12) -* (bluefox) fixed columns resizing in adapters + +- (bluefox) fixed columns resizing in adapters ### 0.6.0 (2015-10-07) -* (bluefox) enable table resizing -* (bluefox) enable auto update of repositories -* (bluefox) implement certificate upload per drug and drop and file selector + +- (bluefox) enable table resizing +- (bluefox) enable auto update of repositories +- (bluefox) implement certificate upload per drug and drop and file selector ### 0.5.13 (2015-09-26) -* (bluefox) add to ace editor the javascript option + +- (bluefox) add to ace editor the javascript option ### 0.5.12 (2015-09-26) -* (bluefox) update ace aditor for json + +- (bluefox) update ace aditor for json ### 0.5.11 (2015-09-15) -* (bluefox) create state of object after attributes editing -* (bluefox) remove common.type=='enum'. It must be a number -* (bluefox) show "level.time" as Time -* (bluefox) fixed: Reiter Objekte: "common.type" verschwindet / Name wird verkurzt -* (bluefox) fixed Multistate-Attribute -* (homoran) Update adminAdapters.js + +- (bluefox) create state of object after attributes editing +- (bluefox) remove common.type=='enum'. It must be a number +- (bluefox) show "level.time" as Time +- (bluefox) fixed: Reiter Objekte: "common.type" verschwindet / Name wird verkurzt +- (bluefox) fixed Multistate-Attribute +- (homoran) Update adminAdapters.js ### 0.5.10 (2015-09-13) -* (bluefox) change "add new object" behaviour -* (bluefox) add "install from custom URL" button (required new js-controller >= 0.7.12) -* (bluefox) add service.png -* (bluefox) show hostst in green if updates available + +- (bluefox) change "add new object" behaviour +- (bluefox) add "install from custom URL" button (required new js-controller >= 0.7.12) +- (bluefox) add service.png +- (bluefox) show hostst in green if updates available ### 0.5.9 (2015-08-26) -* (bluefox) add button "create object" -* (bluefox) Ubersetzungen -* (bluefox) add service group (for terminal) + +- (bluefox) add button "create object" +- (bluefox) Ubersetzungen +- (bluefox) add service group (for terminal) ### 0.5.8 (2015-08-18) -* (bluefox) update select ID dialog -* (bluefox) copy to clipboard functionality + +- (bluefox) update select ID dialog +- (bluefox) copy to clipboard functionality ### 0.5.7 (2015-08-11) -* (bluefox) try to fix log columns -* (bluefox) show boolean in States as enumerations. -* (bluefox) implement upload indicator -* (bluefox) update packages + +- (bluefox) try to fix log columns +- (bluefox) show boolean in States as enumerations. +- (bluefox) implement upload indicator +- (bluefox) update packages ### 0.5.6 (2015-08-05) -* (bluefox) fixed translate.js -* (bluefox) support of multilanguage for tabs -* (bluefox) improve selectID.js -* (bluefox) store settings of selectId dialog + +- (bluefox) fixed translate.js +- (bluefox) support of multilanguage for tabs +- (bluefox) improve selectID.js +- (bluefox) store settings of selectId dialog ### 0.5.5 (2015-07-29) -* (bluefox) update packages + +- (bluefox) update packages ### 0.5.4 (2015-07-01) -* (bluefox) fixed error in "create new group" + +- (bluefox) fixed error in "create new group" ### 0.5.3 (2015-06-29) -* (bluefox) enable select objects in javascript + +- (bluefox) enable select objects in javascript ### 0.5.2 (2015-06-29) -* (bluefox) fixed delete objects -* (bluefox) fixed vis group + +- (bluefox) fixed delete objects +- (bluefox) fixed vis group ### 0.5.1 (2015-06-28) -* (bluefox) support of permissions -* (bluefox) confirm deleting of scripts -* (bluefox) fixed license agreement for adapters -* (SmilingJack) fixed scroll by adapter config -* (bluefox) support of https link in instances -* (bluefox) fixed buttons after sort in jqGrid table -* (siedi)implement multiselect for selectID tree -* (bluefox) better edit object in raw mode. -* (bluefox) adjustable tabs + +- (bluefox) support of permissions +- (bluefox) confirm deleting of scripts +- (bluefox) fixed license agreement for adapters +- (SmilingJack) fixed scroll by adapter config +- (bluefox) support of https link in instances +- (bluefox) fixed buttons after sort in jqGrid table +- (siedi)implement multiselect for selectID tree +- (bluefox) better edit object in raw mode. +- (bluefox) adjustable tabs ### 0.5.0 (2015-06-12) -* (bluefox) support of permissions + +- (bluefox) support of permissions ### 0.4.8 (2015-05-17) -* (bluefox) fixed buttons after sort in jqGrid table + +- (bluefox) fixed buttons after sort in jqGrid table ### 0.4.7 (2015-05-13) -* (bluefox) fixed license agreement for adapters -* (SmilingJack) fixed scroll by adapter config + +- (bluefox) fixed license agreement for adapters +- (SmilingJack) fixed scroll by adapter config ### 0.4.6 (2015-05-01) -* (bluefox) confirm deleting of scripts + +- (bluefox) confirm deleting of scripts ### 0.4.5 (2015-04-24) -* (SmilingJack) update jquery ui to 1.11.4 -* (bluefox) remove unused libs -* (bluefox) set missing categories + +- (SmilingJack) update jquery ui to 1.11.4 +- (bluefox) remove unused libs +- (bluefox) set missing categories ### 0.4.4 (2015-04-19) -* (bluefox) fixed error with hm-rega instance + +- (bluefox) fixed error with hm-rega instance ### 0.4.3 (2015-04-19) -* (bluefox) fixed error with select ID dialog in edit script -* (bluefox) fixed group of installed adapter -* (bluefox) show statistics over installed adapters -* (bluefox) add "agree with statistics" checkbox + +- (bluefox) fixed error with select ID dialog in edit script +- (bluefox) fixed group of installed adapter +- (bluefox) show statistics over installed adapters +- (bluefox) add "agree with statistics" checkbox ### 0.4.2 (2015-04-17) -* (bluefox) workaround for license text + +- (bluefox) workaround for license text ### 0.4.1 (2015-04-17) -* (bluefox) fixed click on buttons on adapter tab + +- (bluefox) fixed click on buttons on adapter tab ### 0.4.0 (2015-04-16) -* (bluefox) used tree for adapters -* (bluefox) implement license agreement for adapters + +- (bluefox) used tree for adapters +- (bluefox) implement license agreement for adapters ### 0.3.27 (2015-04-14) -* (bluefox) save size of script editor dialog -* (bluefox) fixed errors with table editor in adapter configuration -* (bluefox) update npm modules + +- (bluefox) save size of script editor dialog +- (bluefox) fixed errors with table editor in adapter configuration +- (bluefox) update npm modules ### 0.3.26 (2015-03-27) -* (bluefox) change save function for adapter settings -* (bluefox) fixed show states in object tab + +- (bluefox) change save function for adapter settings +- (bluefox) fixed show states in object tab ### 0.3.23 (2015-03-22) -* (bluefox) fixed error with show values in objects TAB -* (bluefox) move objects tab code into adminObjects.js + +- (bluefox) fixed error with show values in objects TAB +- (bluefox) move objects tab code into adminObjects.js ### 0.3.22 (2015-03-20) -* (bluefox) move states to extra file -* (bluefox) speed up rendering of states -* (bluefox) store some filter settings (not all yet) -* (bluefox) support of width and height settings for configuration dialog of adapter instance -* (bluefox) enable read and upload of files (for sayit) + +- (bluefox) move states to extra file +- (bluefox) speed up rendering of states +- (bluefox) store some filter settings (not all yet) +- (bluefox) support of width and height settings for configuration dialog of adapter instance +- (bluefox) enable read and upload of files (for sayit) ### 0.3.21 (2015-03-08) -* (bluefox) fixed filter in log + +- (bluefox) fixed filter in log ### 0.3.20 (2015-03-07) -* (bluefox) support of uncolored log messages -* (bluefox) place logs in own file + +- (bluefox) support of uncolored log messages +- (bluefox) place logs in own file ### 0.3.19 (2015-03-04) -* (bluefox) fixed some errors with restart + +- (bluefox) fixed some errors with restart ### 0.3.18 (2015-02-22) -* (bluefox) fixed error with delete button for adapters + +- (bluefox) fixed error with delete button for adapters ### 0.3.17 (2015-02-22) -* (bluefox) fixed error with refresh button for adapters (again) + +- (bluefox) fixed error with refresh button for adapters (again) ### 0.3.16 (2015-02-21) -* (bluefox) fixed error with refresh button for adapters + +- (bluefox) fixed error with refresh button for adapters ### 0.3.15 (2015-01-26) -* (bluefox) extend table editor in adapter settings -* (bluefox) fixed error in instances. + +- (bluefox) extend table editor in adapter settings +- (bluefox) fixed error in instances. ### 0.3.14 (2015-01-26) -* (bluefox) fixed error with adapter instances with more modes (again) + +- (bluefox) fixed error with adapter instances with more modes (again) ### 0.3.13 (2015-01-21) -* (bluefox) add selection of certificates to settings of admin -* (bluefox) make showMessage dialog + +- (bluefox) add selection of certificates to settings of admin +- (bluefox) make showMessage dialog ### 0.3.12 (2015-01-20) -* (bluefox) add selection of certificates to settings of admin -* (bluefox) make showMessage dialog + +- (bluefox) add selection of certificates to settings of admin +- (bluefox) make showMessage dialog ### 0.3.11 (2015-01-16) -* (bluefox) fixed npm + +- (bluefox) fixed npm ### 0.3.10 (2015-01-14) -* (bluefox) fixed error with adapter instances with more modes + +- (bluefox) fixed error with adapter instances with more modes ### 0.3.9 (2015-01-10) -* (bluefox) support of multiple hosts if one host is down. + +- (bluefox) support of multiple hosts if one host is down. ### 0.3.8 (2015-01-08) -* (bluefox) fixed errors with states update if filtered. Resize command putput window. + +- (bluefox) fixed errors with states update if filtered. Resize command putput window. ### 0.3.7 (2015-01-07) -* (bluefox) fixed errors with history state update. + +- (bluefox) fixed errors with history state update. ### 0.3.6 (2015-01-07) -* (bluefox) group edit of history settings. Move history settings from states to objects. + +- (bluefox) group edit of history settings. Move history settings from states to objects. ### 0.3.5 (2015-01-06) -* (bluefox) add events filter. Fix error with alive and connected status. + +- (bluefox) add events filter. Fix error with alive and connected status. ### 0.3.4 (2015-01-04) -* (bluefox) fixed error with update adapters with "-" in name, like hm-rpc or hm-rega + +- (bluefox) fixed error with update adapters with "-" in name, like hm-rpc or hm-rega ### 0.3.3 (2015-01-03) -* (bluefox) fixed error if states without object + +- (bluefox) fixed error if states without object ### 0.3.2 (2015-01-02) -* (bluefox) fixed error if states without object + +- (bluefox) fixed error if states without object ### 0.3.1 (2015-01-02) -* (bluefox) Support of npm install + +- (bluefox) Support of npm install ### 0.3.0 (2014-12-25) -* (bluefox) Support of debounce interval for history + +- (bluefox) Support of debounce interval for history ### 0.2.9 (2014-12-20) -* (bluefox) fixed filter of IDs in objects + +- (bluefox) fixed filter of IDs in objects ### 0.2.8 (2014-12-20) -* (bluefox) support of controller restart + +- (bluefox) support of controller restart ### 0.2.7 (2014-12-19) -* (bluefox) fixed time in log (web) -* (bluefox) replace enum edit with tree + +- (bluefox) fixed time in log (web) +- (bluefox) replace enum edit with tree ### 0.2.6 (2014-12-16) -* (bluefox) replace jqGrid with fancytree by objects + +- (bluefox) replace jqGrid with fancytree by objects ### 0.2.5 (2014-12-07) -* (bluefox) fixed object tree (some nodes was hidden) + +- (bluefox) fixed object tree (some nodes was hidden) ### 0.2.4 (2014-12-05) -* (bluefox) preload last 200 lines from iobroker.log + +- (bluefox) preload last 200 lines from iobroker.log ### 0.2.3 (2014-12-04) -* (bluefox) install adapter with npm + +- (bluefox) install adapter with npm ### 0.2.2 (2014-11-29) -* (bluefox) Set language settings after license confirmed -* (bluefox) try to use npm installer for this adapter + +- (bluefox) Set language settings after license confirmed +- (bluefox) try to use npm installer for this adapter ### 0.2.1 (2014-11-26) -* (bluefox) Charts in history dialog -* (bluefox) filter states by history -* (bluefox) show only 500 events + +- (bluefox) Charts in history dialog +- (bluefox) filter states by history +- (bluefox) show only 500 events ### 0.2.0 (2014-11-20) -* (bluefox) support of no-"io." schema -* (bluefox) better enum editing -* (bluefox) update of object tree online + +- (bluefox) support of no-"io." schema +- (bluefox) better enum editing +- (bluefox) update of object tree online ### 0.1.9 (2014-11-15) -* (bluefox) fixed scripts editor + +- (bluefox) fixed scripts editor ### 0.1.8 (2014-11-10) -* (bluefox) fixed problem if js-controller does not hav the most actual version + +- (bluefox) fixed problem if js-controller does not hav the most actual version ### 0.1.7 (2014-11-09) -* (bluefox) add log pane + +- (bluefox) add log pane ### 0.1.6 (2014-11-07) -* (bluefox) fixed edit list in configuration + +- (bluefox) fixed edit list in configuration ### 0.1.5 (2014-11-03) -* (bluefox) support of tables in edit configuration + +- (bluefox) support of tables in edit configuration ### 0.1.4 (2014-11-01) -* (bluefox) update history dialog live (add new values on the fly to history table) + +- (bluefox) update history dialog live (add new values on the fly to history table) ### 0.1.3 (2014-11-01) -* (bluefox) add link to web service of adapter instance + +- (bluefox) add link to web service of adapter instance ### 0.1.2 (2014-11-01) -* (bluefox) add functions to edit lists in adapter config + +- (bluefox) add functions to edit lists in adapter config ### 0.1.1 (2014-10-30) -* (bluefox) support of sendToHost command for adapter config. + +- (bluefox) support of sendToHost command for adapter config. ### 0.1.0 (2014-10-29) -* (bluefox) update states if some adapter added or deleted. Update states if history enabled or disabled. + +- (bluefox) update states if some adapter added or deleted. Update states if history enabled or disabled. ### 0.0.19 (2014-10-24) -* (bluefox) fixed error with repository edition + +- (bluefox) fixed error with repository edition ### 0.0.18 (2014-10-20) -* (bluefox) fixed error with "up to date" + +- (bluefox) fixed error with "up to date" ### 0.0.17 (2014-10-19) -* (bluefox) fixed delete of adapter + +- (bluefox) fixed delete of adapter ### 0.0.16 (2014-10-19) -* (bluefox) support of a certificate list + +- (bluefox) support of a certificate list ### 0.0.15 (2014-10-09) -* (bluefox) make possible availableModes for adapter -* (bluefox) add auto changelog -* (bluefox) improve Grunt -* (bluefox) by default enabled. + +- (bluefox) make possible availableModes for adapter +- (bluefox) add auto changelog +- (bluefox) improve Grunt +- (bluefox) by default enabled. ### 0.0.14 -* (bluefox) add repositories editor + +- (bluefox) add repositories editor ### 0.0.13 -* (hobbyquaker) gridAdapter style -* (hobbyquaker) moved system settings to dialog + +- (hobbyquaker) gridAdapter style +- (hobbyquaker) moved system settings to dialog ### 0.0.12 -* (bluefox) new concept of updates/upgrades + +- (bluefox) new concept of updates/upgrades ### 0.0.11 -* (hobbyquaker) bugfix - slashes in IDs -* (hobbyquaker) bugfix - gridHistory + +- (hobbyquaker) bugfix - slashes in IDs +- (hobbyquaker) bugfix - gridHistory ### 0.0.10 -* (hobbyquaker) more options in dialogHistory -* (hobbyquaker) add enums -* (hobbyquaker) hide not-implemented buttons (add/del object f.e.) -* (hobbyquaker) prepared tab log -* (hobbyquaker) gridAdapters: colors for release state (red = planned, orange = alpha, yellow = beta, green = stable) + +- (hobbyquaker) more options in dialogHistory +- (hobbyquaker) add enums +- (hobbyquaker) hide not-implemented buttons (add/del object f.e.) +- (hobbyquaker) prepared tab log +- (hobbyquaker) gridAdapters: colors for release state (red = planned, orange = alpha, yellow = beta, green = stable) ### 0.0.9 -* (hobbyquaker) history + +- (hobbyquaker) history ### 0.0.8 -* (hobbyquaker) added column "parent name" to gridStates + +- (hobbyquaker) added column "parent name" to gridStates ### 0.0.7 -* (hobbyquaker) prepared enum members -* (hobbyquaker) hide logout button if auth disabled -* (hobbyquaker) refactoring -* (hobbyquaker) fixes + +- (hobbyquaker) prepared enum members +- (hobbyquaker) hide logout button if auth disabled +- (hobbyquaker) refactoring +- (hobbyquaker) fixes ### 0.0.5 -* (hobbyquaker) show an available version, show update button if not up-to-date -* (hobbyquaker) minor fixes + +- (hobbyquaker) show an available version, show update button if not up-to-date +- (hobbyquaker) minor fixes diff --git a/DEVELOPER.md b/DEVELOPER.md index 0527174ab..16ab6ade6 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -1,5 +1,7 @@ -## Development -### Getting started +# Development + +## Getting started + If you want to contribute to the Admin adapter, follow these steps: Install all packages all in one via @@ -32,12 +34,13 @@ npm run start You now have the admin UI running on port `3000` with hot code reload from your local project. ### Guidelines -The packages in the workspace folder (`packages`) should not contain any `devDependencies`, all `devDependencies` should be added to the root `package.json`. + +The packages in the workspace folder (`packages`) should not contain any `devDependencies`, all `devDependencies` should be added to the root `package.json`. There is one exception to this rule: defining dependencies between workspace packages should be done via defining them as development dependency to ensure `lerna` is respecting the build order. ## How to install from GitHub -``` +```bash npm install cd node_modules/iobroker.admin npm install @@ -49,10 +52,19 @@ iobroker upload admin Since Admin 6.2.14, there is a convenience support for OAuth authentication flows that send the user to the authorization server and then redirect the user back to complete the process. -### Sending user to the Authorization server -In JSON-Config you can use the sendTo component to send a message to your adapter which then as response return a URL. The component can then open this URL automatically in a new tab/window. +### Short explanation: OAuth2.0 Authentication flow + +There is a possibility to use OAuth2.0 authentication for other services. Admin has an endpoint `oauth2_callbacks`. + +The calls like `http(s)://ip:port/oauth2_callbacks/adapterName.X/?state=ABC&code=123¶m=true¶m2` will be processed and the special message `oauth2Callback` will be sent to `adapterName.X` instance with query parameters `{"state": "ABC", "code": 123, "param": true, "param2": true}`. + +As mandatory response the admin expects the object like: `{"result": "Show this text to user by success", "error": "ERROR: Result will be ignored"}`. The result or error will be shown to the user. Please send already translated messages. + +### Long explanation: Sending user to the Authorization server + +In JSON-Config, you can use the sendTo component to send a message to your adapter which then as response return a URL. The component can then open this URL automatically in a new tab/window. -**This only works if the URL for redirecting back after the authentication do not need to be specified hardcoded in the configurationnof the client!** +**This only works if the URL for redirecting back after the authentication does not need to be specified hardcoded in the configuration of the client!** ```json "_authenticate": { @@ -73,93 +85,318 @@ In JSON-Config you can use the sendTo component to send a message to your adapte } ``` -Important is that you also send "data._origin" to your adapter and use this to construct the "redirect back url". This URL will point to the current admin page to a magic URL (more infos below) +Important is that you also send `data.\_origin` to your adapter and use this to construct the "redirect back url". This URL will point to the current admin page to a magic URL (the more info below) When providing "openUrl" property in the configuration Admin then expects a property "openUrl" in the response object from the message which is used as URL for the new window. -In your adapter code you so can build the redirect URL as required and return it as response like this: +In your adapter code, you can build the redirect URL as required and return it as a response like this: ```javascript const redirect_uri = `${args.redirect_uri_base}oauth2_callbacks/${adapter.namespace}/`; // Add the magic route in Admin -const redirectUrl = `https://...?...&redirect_url=${encodeURIComponent(redirect_uri)}`// Now use this to construct the link to the partner -obj.callback && adapter.sendTo(obj.from, obj.command, {openUrl: redirectUrl}, obj.callback); // send response +const redirectUrl = `https://...?...&redirect_url=${encodeURIComponent(redirect_uri)}`; // Now use this to construct the link to the partner +obj.callback && adapter.sendTo(obj.from, obj.command, { openUrl: redirectUrl }, obj.callback); // send response ``` -Usually you also construct a state parameter as unique ID and so it is a good option to store the relevant data using the state string like cope configuration or such because it will normally not being returned. +Usually you also construct a state parameter as a unique ID, and so it is a good option to store the relevant data using the state string like cope configuration or such because it will normally not be returned. -As soon as the authentication is done the user is redirected to the given Redirect URL the magic admin route /oauth2_callbacks// is opened in the browser. This will send a message with the defined name "oauth2Callback" to the provided adapter instance. -The message contains the Query-parameters provided in the request as object. +As soon as the authentication is done, the user is redirected to the given Redirect URL the magic admin route `/oauth2_callbacks//` is opened in the browser. This will send a message with the defined name `oauth2Callback` to the provided adapter instance. +The message contains the Query-parameters provided in the request as an object. -Parameters like "?state=ABC&code=DEF" would be received in the message as +Parameters like `?state=ABC&code=DEF` would be received in the message as ```json { - "state":"ABC", - "code":"DEF" + "state": "ABC", + "code": "DEF" } ``` -With these information you can easily exchange the code for an access token and so on and complete the authentication process. +With this information, you can easily exchange the code for an access token and so on and complete the authentication process. -You need to return a response to the "oauth2Callback" message to allow Admin to show a proper page to the user. +You need to return a response to the `oauth2Callback` message to allow Admin to show a proper page to the user. ```javascript if (error) { - obj.callback && adapter.sendTo(obj.from, obj.command, {error: `Authentiction error: ${error}. Please try again.`}, obj.callback); + obj.callback && + adapter.sendTo( + obj.from, + obj.command, + { error: `Authentiction error: ${error}. Please try again.` }, + obj.callback, + ); } else { - obj.callback && adapter.sendTo(obj.from, obj.command, {result: 'Tokens updated successfully. Please reload configuration.'}, obj.callback); + obj.callback && + adapter.sendTo( + obj.from, + obj.command, + { result: 'Tokens updated successfully. Please reload configuration.' }, + obj.callback, + ); } ``` -## How to show help information in configuration dialog (Material-UI) +## Dynamic Interface in Notifications + +Starting from [js-controller v5.x](https://github.com/ioBroker/ioBroker.js-controller/blob/master/README.md#notification-system), developers can send system notifications that are visible in the admin interface. + +In js-controller v7.x, this feature has been extended to allow adapters to send not only static information but also dynamic GUIs using the [JSON-Config schema](packages/jsonConfig/SCHEMA.md). -Help can be a combination of tooltip, link and text. +### Generating Notifications +To display a dynamic GUI (with tables, buttons, colored texts, etc.), developers should generate notifications in the following form: + +```js +await adapter.registerNotification( + 'adapterName', + 'notificationScope', // defined in io-package.json => notifications + I18n.translate('New dynamic notification: %s', new Date().toLocaleString()), + { + // contextData indicates that your adapter supports dynamic GUI + contextData: { + admin: { + notification: { + offlineMessage: I18n.getTranslatedObject('Instance is offline'), + specificUserData, + }, + }, + }, + }, +); ``` - - + + + + +
+ + + +
``` -id will be found automatically in the previous td. +ID will be found automatically in the previous td. -``` +```html - + + + + + +
+ + + +
``` id set with data-id. -``` +```html - + + + + +
+ + + +
``` -Link will be generated automatically from common.readme and '#param1'. -e.g. if - -```common.readme = https://github.com/ioBroker/ioBroker.admin/blob/master/README.md``` +The link will be generated automatically from `common.readme` and `#param1`. +e.g., if -link will be ```https://github.com/ioBroker/ioBroker.admin/blob/master/README.md#param1``` +`common.readme = https://github.com/ioBroker/ioBroker.admin/blob/master/README.md` +link will be https://github.com/ioBroker/ioBroker.admin/blob/master/README.md#param1` -``` +```html - + + + + +
+ + + +
``` -link will be ```https://github.com/ioBroker/ioBroker.admin/blob/master/README.md#my-param-description``` -``` +link will be `https://github.com/ioBroker/ioBroker.admin/blob/master/README.md#my-param-description` + +```html - + + + + +
+ + + +
``` + link will taken from data-link. diff --git a/README.md b/README.md index 4333f3226..1b22b154b 100644 --- a/README.md +++ b/README.md @@ -15,18 +15,21 @@ User interface for configuration and administration of ioBroker. **This adapter uses Sentry libraries to automatically report exceptions and code errors to the developers.** For more details and for information how to disable the error reporting see [Sentry-Plugin Documentation](https://github.com/ioBroker/plugin-sentry#plugin-sentry)! Sentry reporting is used starting with js-controller 3.0. ## JSON config schema + The JSON config schema description can be found at [JSON config schema](/packages/jsonConfig/SCHEMA.md). ## Using common.localLink -- `%ip%` - ioBroker ip address (address of the admin) -- `%secure%` or `%protocol%` - read from `native.secure` the value and use http or https -- `%web_protocol%` - looking for the first instance of web (e.g., `web.0`) and get `native.secure` from `system.adapter.web.0` -- `%instance%` - instance of the adapter -- `%someField%` - get someField from `native` of this adapter instance -- `%web.0_bind%` - get `native.bind` from `system.adapter.web.0` -- `%native_someField%` - get someField from `native` of this adapter instance + +- `%ip%` - ioBroker ip address (address of the admin) +- `%secure%` or `%protocol%` - read from `native.secure` the value and use http or https +- `%web_protocol%` - looking for the first instance of web (e.g., `web.0`) and get `native.secure` from `system.adapter.web.0` +- `%instance%` - instance of the adapter +- `%someField%` - get someField from `native` of this adapter instance +- `%web.0_bind%` - get `native.bind` from `system.adapter.web.0` +- `%native_someField%` - get someField from `native` of this adapter instance ## Scheduled restart + Some adapters are not stable or connection disappears after one or two days. To fix this, there is a scheduled restart setting. To activate scheduled restart, just define CRON condition when to restart adapter. @@ -34,12 +37,14 @@ To activate scheduled restart, just define CRON condition when to restart adapte It is suggested to restart in the night, when no one use the adapter, e.g. `0 3 * * *` - at 3:00 every day. ## Let's Encrypt Certificates + To manage and update, let's encrypt certificates you need to use [`iobroker.acme`](https://github.com/iobroker-community-adapters/ioBroker.acme) adapter. You will have so-called "collections" of certificates. Each collection has its own domains. You can select in configuration of admin adapter if and which collection to use. ## Simple instance's settings page + The user has the possibility to limit the access to the instance configuration dialog. For that, the option "Allow access only to specific instances" must be activated. It could be found on the "Access to the instances" tab. @@ -48,13 +53,15 @@ Additionally, the allowed instances should be selected in the appeared configura If this option is disabled, the simple configuration page could be accessed under `http://IP:8081/configs.html` ## Reverse proxy + Please be sure that you forward not only the http/https requests, but the web-socket traffic too. It is essential for communication. From version 6.1.0 you have the possibility to tune intro page for usage with reverse proxy. -### Example -Your `ioBroker.admin` runs on port 8081 behind reverse proxy with domain `iobroker.mydomain.com` under path `/ioBrokerAdmin/`. -And you set up e.g., nginx to forward the requests to the `http://local-iobroker.IP:8081`. +### Example + +Your `ioBroker.admin` runs on port 8081 behind reverse proxy with domain `iobroker.mydomain.com` under path `/ioBrokerAdmin/`. +And you set up e.g., nginx to forward the requests to the `http://local-iobroker.IP:8081`. The same is with your web instance: `https://iobroker.mydomain.com/ioBrokerWeb/ => http://local-iobroker.IP:8082`. And with rest-api instance: `https://iobroker.mydomain.com/ioBrokerAPI/ => http://local-iobroker.IP:8093`. @@ -62,7 +69,7 @@ And with rest-api instance: `https://iobroker.mydomain.com/ioBrokerAPI/ => http: You can add the following lines into Reverse Proxy tab to let Intro tab run behind reverse proxy properly: | Global path | Instance | Instance path behind proxy | -|-------------------|---------------|----------------------------| +| ----------------- | ------------- | -------------------------- | | `/ioBrokerAdmin/` | `web.0` | `/ioBrokerWeb/` | | | `rest-api.0` | `/ioBrokerAPI/` | | | `admin.0` | `/ioBrokerAdmin/` | @@ -70,14 +77,8 @@ You can add the following lines into Reverse Proxy tab to let Intro tab run behi So all links of instances that use web server, like `eventlist`, `vis`, `material` and so on will use `https://iobroker.mydomain.com/ioBrokerWeb/` path -## OAuth2.0 Authentication flow -There is a possibility to use OAuth2.0 authentication for other services. Admin has an endpoint `oauth2_callbacks`. - -The calls like `http(s)://ip:port/oauth2_callbacks/adapterName.X/?state=ABC&code=123¶m=true¶m2` will be processed and the special message `oauth2Callback` will be sent to `adapterName.X` instance with query parameters `{"state": "ABC", "code": 123, "param": true, "param2": true}`. - -As mandatory response the admin expects the object like: `{"result": "Show this text to user by success", "error": "ERROR: Result will be ignored"}`. The result or error will be shown to the user. Please send already translated messages. - ## Used icons + This project uses icons from [Flaticon](https://www.flaticon.com/). ioBroker GmbH has a valid license for all used icons. @@ -86,35 +87,36 @@ The icons may not be reused in other projects without the proper flaticon licens +### 7.2.0 (2024-10-01) -### **WORK IN PROGRESS** - -* (@GermanBluefox) Added the history for the installation from URL -* (@foxriver76) fixed wrongly displayed repository warning +- (@GermanBluefox) Added the check of well-known passwords for the linux systems +- (@GermanBluefox) Added the history for the installation from URL +- (@foxriver76) fixed wrongly displayed repository warning ### 7.1.5 (2024-09-26) -* (bluefox) Added the read-only flag to the `state` JSON Config component + +- (bluefox) Added the read-only flag to the `state` JSON Config component ### 7.1.3 (2024-09-20) -* (@foxriver76) improve appearance and standardization of some warning messages -* (@foxriver76) indicate `alert` warnings by the badge color on the notification button -* (@foxriver76) allow distinguishing between alert notifications and others for host notifications -* (@foxriver76) do not automatically open the notification dialog without user interaction -* (@foxriver76) fixed logging as a socket client is now throwing real errors + +- (@foxriver76) improve appearance and standardization of some warning messages +- (@foxriver76) indicate `alert` warnings by the badge color on the notification button +- (@foxriver76) allow distinguishing between alert notifications and others for host notifications +- (@foxriver76) do not automatically open the notification dialog without user interaction +- (@foxriver76) fixed logging as a socket client is now throwing real errors ### 7.1.2 (2024-09-20) -* (@foxriver76) fixed host base settings dialog + +- (@foxriver76) fixed host base settings dialog ### 7.1.1 (2024-09-15) -* (bluefox) Showed the context menu under cursor position in the object browser -* (bluefox) Added links to aliases in the object browser -* (bluefox) Added confirmation for CRON dialog if set to triggering every minute -### 7.1.0 (2024-09-02) -* (bluefox) Added the possibility to show button in notifications -* (bluefox) Removed gulp from the build process +- (bluefox) Showed the context menu under cursor position in the object browser +- (bluefox) Added links to aliases in the object browser +- (bluefox) Added confirmation for CRON dialog if set to triggering every minute ## License + The MIT License (MIT) Copyright (c) 2014-2024 bluefox diff --git a/lerna.json b/lerna.json index 79cd8685b..9016a3b9d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "7.1.5", + "version": "7.2.0", "packages": [ "packages/*" ], diff --git a/package-lock.json b/package-lock.json index 598634cf3..af4d51f68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,25 +32,25 @@ "@dilesoft/vite-plugin-federation-dynamic": "^1.1.9", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@fnando/sparkline": "^0.3.10", - "@foxriver76/iob-component-lib": "^0.1.5", + "@foxriver76/iob-component-lib": "^0.1.6", "@honkhonk/vite-plugin-svgr": "^1.1.0", - "@iobroker/adapter-react-v5": "^7.1.4", + "@iobroker/adapter-react-v5": "^7.2.1", "@iobroker/admin-component-easy-access": "^1.0.1", - "@iobroker/build-tools": "^1.0.2", + "@iobroker/build-tools": "^1.1.0", "@iobroker/dm-utils": "^0.5.0", - "@iobroker/eslint-config": "^0.1.5", + "@iobroker/eslint-config": "^0.1.6", "@iobroker/js-controller-common-db": "^6.0.12-alpha.0-20240913-9a3639aed", "@iobroker/legacy-testing": "^1.0.13", - "@iobroker/socket-client": "^3.0.1", + "@iobroker/socket-client": "^3.1.0", "@iobroker/testing": "^5.0.0", - "@iobroker/types": "^6.0.12-alpha.0-20240913-9a3639aed", - "@mui/icons-material": "^6.1.0", - "@mui/material": "^6.1.0", - "@mui/x-data-grid": "^7.17.0", - "@mui/x-date-pickers": "^7.17.0", + "@iobroker/types": "^7.0.0-alpha.1-20241001-61327866b", + "@mui/icons-material": "^6.1.1", + "@mui/material": "^6.1.1", + "@mui/x-data-grid": "^7.18.0", + "@mui/x-date-pickers": "^7.18.0", "@originjs/vite-plugin-commonjs": "^1.0.3", "@react-leaflet/core": "^2.1.0", - "@sentry/browser": "^8.30.0", + "@sentry/browser": "^8.33.1", "@testing-library/jest-dom": "^6.5.0", "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.5.2", @@ -66,17 +66,15 @@ "@types/express-session": "^1.18.0", "@types/leaflet": "^1.9.12", "@types/less": "^3.0.6", - "@types/lodash": "^4.17.7", + "@types/lodash": "^4.17.9", "@types/mocha": "^10.0.8", - "@types/node": "^22.5.5", + "@types/node": "^22.7.4", "@types/passport": "^1.0.16", "@types/passport-local": "^1.0.38", - "@types/react": "^18.3.5", + "@types/react": "^18.3.10", "@types/react-color": "^3.0.12", "@types/react-dom": "^18.3.0", - "@types/validator": "^13.12.1", - "@typescript-eslint/eslint-plugin": "^8.6.0", - "@typescript-eslint/parser": "^8.5.0", + "@types/validator": "^13.12.2", "babel": "^6.23.0", "babel-plugin-inline-json-import": "^0.3.2", "buffer": "^6.0.3", @@ -88,7 +86,7 @@ "cron-parser": "^4.9.0", "cronstrue": "^2.50.0", "crypto-js": "^4.2.0", - "date-fns": "^3.6.0", + "date-fns": "^4.1.0", "echarts": "^5.5.1", "echarts-for-react": "^3.0.2", "globals": "^15.9.0", @@ -102,10 +100,10 @@ "lodash": "^4.17.21", "mocha": "^10.7.3", "moment": "^2.30.1", - "ol": "^10.1.0", + "ol": "^10.2.1", "prettier": "^3.3.3", "prop-types": "^15.8.1", - "puppeteer": "^23.3.0", + "puppeteer": "^23.4.1", "react": "^18.3.1", "react-ace": "^12.0.0", "react-color": "^2.19.3", @@ -134,10 +132,10 @@ "typescript": "^5.6.2" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.7.3", - "@nx/nx-darwin-x64": "19.7.3", - "@nx/nx-linux-x64-gnu": "19.7.4", - "@nx/nx-win32-x64-msvc": "19.7.4" + "@nx/nx-darwin-arm64": "19.8.2", + "@nx/nx-darwin-x64": "19.8.2", + "@nx/nx-linux-x64-gnu": "19.8.2", + "@nx/nx-win32-x64-msvc": "19.8.2" } }, "node_modules/@adobe/css-tools": { @@ -3035,9 +3033,9 @@ "license": "MIT" }, "node_modules/@foxriver76/iob-component-lib": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@foxriver76/iob-component-lib/-/iob-component-lib-0.1.5.tgz", - "integrity": "sha512-4zO0Tf9yATzGRVLyF46kwv9IOdn3RH3w/l2lBVVWhliIB4TFCHYu3vJ8ciJ4aJWbSiF8JF6T/DKEy/GKWc/9Yw==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@foxriver76/iob-component-lib/-/iob-component-lib-0.1.6.tgz", + "integrity": "sha512-rw0jdn7sZVePZ8/jHikkqfHMlMqvkprrNK7N1AHvnrNFy9saaayLNGO8s2sM2c7waKahvk8MPoa3L92q2wn4BQ==", "dev": true }, "node_modules/@gar/promisify": { @@ -3171,19 +3169,21 @@ } }, "node_modules/@iobroker/adapter-react-v5": { - "version": "7.1.4", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@iobroker/adapter-react-v5/-/adapter-react-v5-7.2.1.tgz", + "integrity": "sha512-fVuWeg2IeBwW27amI88xqwM7FRXxL+xELp/KwythImPc0Q2rySj4umcqZmb1in0APDnKfOtiqz2LWkFEquOzUA==", "license": "MIT", "dependencies": { "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@iobroker/js-controller-common": "^6.0.11", "@iobroker/js-controller-common-db": "^6.0.11", - "@iobroker/socket-client": "^3.0.1", + "@iobroker/socket-client": "^3.1.0", "@iobroker/types": "^6.0.11", - "@mui/icons-material": "^6.1.0", - "@mui/material": "^6.1.0", - "@mui/x-date-pickers": "^7.17.0", - "@sentry/browser": "^8.30.0", + "@mui/icons-material": "^6.1.1", + "@mui/material": "^6.1.1", + "@mui/x-date-pickers": "^7.18.0", + "@sentry/browser": "^8.32.0", "cronstrue": "^2.50.0", "react-color": "^2.19.3", "react-colorful": "^5.6.1", @@ -3264,7 +3264,9 @@ "license": "MIT" }, "node_modules/@iobroker/build-tools": { - "version": "1.0.2", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@iobroker/build-tools/-/build-tools-1.1.0.tgz", + "integrity": "sha512-DcGQr4nTD5htcRADGwo1jQXrdcCwKMiSgq4VIPC1EkTj5FHS6ZiyRrr3rF4ypzCUUeycXAqU+3l7WITnCZmhUQ==", "dev": true, "engines": { "node": ">=16" @@ -3689,7 +3691,9 @@ } }, "node_modules/@iobroker/socket-client": { - "version": "3.0.1", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@iobroker/socket-client/-/socket-client-3.1.0.tgz", + "integrity": "sha512-HXMqF7FAieWuzNQ1iKKXVt/8RpPMVc+QXuvUkN+qjsuYgbdV1t8cRHWt0fSuDNS123nrL94qMn1Y/xH2vTFx9g==", "license": "MIT" }, "node_modules/@iobroker/testing": { @@ -3721,9 +3725,10 @@ } }, "node_modules/@iobroker/types": { - "version": "6.0.12-alpha.0-20240913-9a3639aed", + "version": "7.0.0-alpha.1-20241001-61327866b", + "resolved": "https://registry.npmjs.org/@iobroker/types/-/types-7.0.0-alpha.1-20241001-61327866b.tgz", + "integrity": "sha512-sTCJsoslIoYdyxDF9idwu3074P6+yr5dTdHKE9RKbqZDHRYLbmqggedVjheDJKRYUWk6ipOqeUWEiHxhFRV1ZA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12.0.0" } @@ -4531,7 +4536,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.1.tgz", + "integrity": "sha512-VdQC1tPIIcZAnf62L2M1eQif0x2vlKg3YK4kGYbtijSH4niEgI21GnstykW1vQIs+Bc6L+Hua2GATYVjilJ22A==", "license": "MIT", "funding": { "type": "opencollective", @@ -4539,7 +4546,9 @@ } }, "node_modules/@mui/icons-material": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.1.tgz", + "integrity": "sha512-sy/YKwcLPW8VcacNP2uWMYR9xyWuwO9NN9FXuGEU90bRshBXj8pdKk+joe3TCW7oviVS3zXLHlc94wQ0jNsQRQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6" @@ -4552,7 +4561,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^6.1.0", + "@mui/material": "^6.1.1", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -4563,14 +4572,16 @@ } }, "node_modules/@mui/material": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.1.tgz", + "integrity": "sha512-b+eULldTqtqTCbN++2BtBWCir/1LwEYw+2mIlOt2GiEUh1EBBw4/wIukGKKNt3xrCZqRA80yLLkV6tF61Lq3cA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/core-downloads-tracker": "^6.1.0", - "@mui/system": "^6.1.0", - "@mui/types": "^7.2.16", - "@mui/utils": "^6.1.0", + "@mui/core-downloads-tracker": "^6.1.1", + "@mui/system": "^6.1.1", + "@mui/types": "^7.2.17", + "@mui/utils": "^6.1.1", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.11", "clsx": "^2.1.1", @@ -4589,7 +4600,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.1.0", + "@mui/material-pigment-css": "^6.1.1", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -4610,11 +4621,13 @@ } }, "node_modules/@mui/material/node_modules/@mui/utils": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.1.tgz", + "integrity": "sha512-HlRrgdJSPbYDXPpoVMWZV8AE7WcFtAk13rWNWAEVWKSanzBBkymjz3km+Th/Srowsh4pf1fTSP1B0L116wQBYw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/types": "^7.2.16", + "@mui/types": "^7.2.17", "@types/prop-types": "^15.7.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -4639,14 +4652,18 @@ }, "node_modules/@mui/material/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, "node_modules/@mui/private-theming": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.1.tgz", + "integrity": "sha512-JlrjIdhyZUtewtdAuUsvi3ZnO0YS49IW4Mfz19ZWTlQ0sDGga6LNPVwHClWr2/zJK2we2BQx9/i8M32rgKuzrg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/utils": "^6.1.0", + "@mui/utils": "^6.1.1", "prop-types": "^15.8.1" }, "engines": { @@ -4667,11 +4684,13 @@ } }, "node_modules/@mui/private-theming/node_modules/@mui/utils": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.1.tgz", + "integrity": "sha512-HlRrgdJSPbYDXPpoVMWZV8AE7WcFtAk13rWNWAEVWKSanzBBkymjz3km+Th/Srowsh4pf1fTSP1B0L116wQBYw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/types": "^7.2.16", + "@mui/types": "^7.2.17", "@types/prop-types": "^15.7.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -4696,10 +4715,14 @@ }, "node_modules/@mui/private-theming/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, "node_modules/@mui/styled-engine": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.1.tgz", + "integrity": "sha512-HJyIoMpFb11fnHuRtUILOXgq6vj4LhIlE8maG4SwP/W+E5sa7HFexhnB3vOMT7bKys4UKNxhobC8jwWxYilGsA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", @@ -4730,14 +4753,16 @@ } }, "node_modules/@mui/system": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.1.tgz", + "integrity": "sha512-PaYsCz2tUOcpu3T0okDEsSuP/yCDIj9JZ4Tox1JovRSKIjltHpXPsXZSGr3RiWdtM1MTQMFMCZzu0+CKbyy+Kw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/private-theming": "^6.1.0", - "@mui/styled-engine": "^6.1.0", - "@mui/types": "^7.2.16", - "@mui/utils": "^6.1.0", + "@mui/private-theming": "^6.1.1", + "@mui/styled-engine": "^6.1.1", + "@mui/types": "^7.2.17", + "@mui/utils": "^6.1.1", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -4768,11 +4793,13 @@ } }, "node_modules/@mui/system/node_modules/@mui/utils": { - "version": "6.1.0", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.1.tgz", + "integrity": "sha512-HlRrgdJSPbYDXPpoVMWZV8AE7WcFtAk13rWNWAEVWKSanzBBkymjz3km+Th/Srowsh4pf1fTSP1B0L116wQBYw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/types": "^7.2.16", + "@mui/types": "^7.2.17", "@types/prop-types": "^15.7.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -4797,10 +4824,14 @@ }, "node_modules/@mui/system/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, "node_modules/@mui/types": { - "version": "7.2.16", + "version": "7.2.17", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.17.tgz", + "integrity": "sha512-oyumoJgB6jDV8JFzRqjBo2daUuHpzDjoO/e3IrRhhHo/FxJlaVhET6mcNrKHUq2E+R+q3ql0qAtvQ4rfWHhAeQ==", "license": "MIT", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -4844,13 +4875,15 @@ "license": "MIT" }, "node_modules/@mui/x-data-grid": { - "version": "7.17.0", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.18.0.tgz", + "integrity": "sha512-41UjJbRxWk+Yk/lfvaO55Pwo5p+F5s3rOTiHLl53ikCT5GuJ5OCCvik0Bi3c6DzTuUBdrEucae2618rydc2DGw==", "dev": true, "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", "@mui/utils": "^5.16.6", - "@mui/x-internals": "7.17.0", + "@mui/x-internals": "7.18.0", "clsx": "^2.1.1", "prop-types": "^15.8.1", "reselect": "^5.1.1" @@ -4880,12 +4913,14 @@ } }, "node_modules/@mui/x-date-pickers": { - "version": "7.17.0", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.18.0.tgz", + "integrity": "sha512-12tXIoMj9vpS8fS/bS3kWPCoVrH38vNGCxgplI0vOnUrN9rJuYJz3agLPJe1S0xciTw+9W8ZSe3soaW+owoz1Q==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", "@mui/utils": "^5.16.6", - "@mui/x-internals": "7.17.0", + "@mui/x-internals": "7.18.0", "@types/react-transition-group": "^4.4.11", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -4903,7 +4938,7 @@ "@emotion/styled": "^11.8.1", "@mui/material": "^5.15.14 || ^6.0.0", "@mui/system": "^5.15.14 || ^6.0.0", - "date-fns": "^2.25.0 || ^3.2.0", + "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0", "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0", "dayjs": "^1.10.7", "luxon": "^3.0.2", @@ -4944,7 +4979,9 @@ } }, "node_modules/@mui/x-internals": { - "version": "7.17.0", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.18.0.tgz", + "integrity": "sha512-lzCHOWIR0cAIY1bGrWSprYerahbnH5C31ql/2OWCEjcngL2NAV1M6oKI2Vp4HheqzJ822c60UyWyapvyjSzY/A==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.6", @@ -5453,9 +5490,9 @@ } }, "node_modules/@nx/nx-darwin-arm64": { - "version": "19.7.3", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.7.3.tgz", - "integrity": "sha512-0dDK0UkMR0vBv4AP/48Q9A+OC2dvpivdt8su/4W/CPADy69M9B5O3jPiK+jTRsLshQG/soC9JG0Rll1BNWymPg==", + "version": "19.8.2", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.8.2.tgz", + "integrity": "sha512-O06sOObpaF3UQrx6R5s0kFOrhrk/N20rKhOMaD5Qxw6lmVr6TGGH1epGpD8ES7ZPS+p7FUtU9/FPHwY02BZfBg==", "cpu": [ "arm64" ], @@ -5469,9 +5506,9 @@ } }, "node_modules/@nx/nx-darwin-x64": { - "version": "19.7.3", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.7.3.tgz", - "integrity": "sha512-hTdv5YY2GQTdT7GwVO7ST27ZzvCmAQvmkEapfnCdy74QsL4gapaXJFvtWLHVfG6qHNRHWXbpdegvR3VswRHZVQ==", + "version": "19.8.2", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.8.2.tgz", + "integrity": "sha512-hRFA7xpnIeMUF5FiDh681fxSx/EzkFYZ+UE/XBfzbc+T1neRy7NB2vMEa/WMsN0+Y5+NXtibx1akEDD6VOqeJA==", "cpu": [ "x64" ], @@ -5549,9 +5586,9 @@ } }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.7.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.7.4.tgz", - "integrity": "sha512-ZKfVMmaBJejS1K0goHYtXyDlQZ3B4xRFkWZBFe/W56VJo5UGJpTunBo5FcT1RC9hXrT1RE6Ane6AdeTLmqi42A==", + "version": "19.8.2", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.8.2.tgz", + "integrity": "sha512-3h4dmIi5Muym18dsiiXQBygPlSAHZNe3PaYo8mLsUsvuAt2ye0XUDcAlHWXOt/FeuVDG1NEGI05vZJvbIIGikQ==", "cpu": [ "x64" ], @@ -5599,9 +5636,9 @@ } }, "node_modules/@nx/nx-win32-x64-msvc": { - "version": "19.7.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.7.4.tgz", - "integrity": "sha512-2Je+RfNxlXBAjCJ01z+bptNkQjjXkuhWIpZmXqUNwf6VGQQL5b43CUqHAAAY1DAbO748rVeYCDU8CiOpSbhslg==", + "version": "19.8.2", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.8.2.tgz", + "integrity": "sha512-rRt+XIZk+ctxhFORWvugqmS07xi52eRS4QpTq8b24ZJKk1Zw0L5opsXAdzughhBzfIpSx4rxnknFlI78DcRPxA==", "cpu": [ "x64" ], @@ -5909,6 +5946,8 @@ }, "node_modules/@puppeteer/browsers": { "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz", + "integrity": "sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -6038,94 +6077,102 @@ "license": "MIT" }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.30.0", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.33.1.tgz", + "integrity": "sha512-TW6/r+Gl5jiXv54iK1xZ3mlVgTS/jaBp4vcQ0xGMdgiQ3WchEPcFSeYovL+YHT3tSud0GZqVtDQCz+5i76puqA==", "dependencies": { - "@sentry/core": "8.30.0", - "@sentry/types": "8.30.0", - "@sentry/utils": "8.30.0" + "@sentry/core": "8.33.1", + "@sentry/types": "8.33.1", + "@sentry/utils": "8.33.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.30.0", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.33.1.tgz", + "integrity": "sha512-qauMRTm3qDaLqZ3ibI03cj4gLF40y0ij65nj+cns6iWxGCtPrO8tjvXFWuQsE7Aye9dGMnBgmv7uN+NTUtC3RA==", "dependencies": { - "@sentry/core": "8.30.0", - "@sentry/types": "8.30.0", - "@sentry/utils": "8.30.0" + "@sentry/core": "8.33.1", + "@sentry/types": "8.33.1", + "@sentry/utils": "8.33.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.30.0", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.33.1.tgz", + "integrity": "sha512-fm4coIOjmanU29NOVN9MyaP4fUCOYytbtFqVSKRFNZQ/xAgNeySiBIbUd6IjujMmnOk9bY0WEUMcdm3Uotjdog==", "dependencies": { - "@sentry-internal/browser-utils": "8.30.0", - "@sentry/core": "8.30.0", - "@sentry/types": "8.30.0", - "@sentry/utils": "8.30.0" + "@sentry-internal/browser-utils": "8.33.1", + "@sentry/core": "8.33.1", + "@sentry/types": "8.33.1", + "@sentry/utils": "8.33.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.30.0", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.33.1.tgz", + "integrity": "sha512-nsxTFTPCT10Ty/v6+AiST3+yotGP1sUb8xqfKB9fPnS1hZHFryp0NnEls7xFjBsBbZPU1GpFkzrk/E6JFzixDQ==", "dependencies": { - "@sentry-internal/replay": "8.30.0", - "@sentry/core": "8.30.0", - "@sentry/types": "8.30.0", - "@sentry/utils": "8.30.0" + "@sentry-internal/replay": "8.33.1", + "@sentry/core": "8.33.1", + "@sentry/types": "8.33.1", + "@sentry/utils": "8.33.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/browser": { - "version": "8.30.0", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.33.1.tgz", + "integrity": "sha512-c6zI/igexkLwZuGk+u8Rj26ChjxGgkhe6ZbKFsXCYaKAp5ep5X7HQRkkqgbxApiqlC0LduHdd/ymzh139JLg8w==", "dependencies": { - "@sentry-internal/browser-utils": "8.30.0", - "@sentry-internal/feedback": "8.30.0", - "@sentry-internal/replay": "8.30.0", - "@sentry-internal/replay-canvas": "8.30.0", - "@sentry/core": "8.30.0", - "@sentry/types": "8.30.0", - "@sentry/utils": "8.30.0" + "@sentry-internal/browser-utils": "8.33.1", + "@sentry-internal/feedback": "8.33.1", + "@sentry-internal/replay": "8.33.1", + "@sentry-internal/replay-canvas": "8.33.1", + "@sentry/core": "8.33.1", + "@sentry/types": "8.33.1", + "@sentry/utils": "8.33.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/core": { - "version": "8.30.0", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.33.1.tgz", + "integrity": "sha512-3SS41suXLFzxL3OQvTMZ6q92ZapELVq2l2SoWlZopcamWhog2Ru0dp2vkunq97kFHb2TzKRTlFH4+4gbT8SJug==", "dependencies": { - "@sentry/types": "8.30.0", - "@sentry/utils": "8.30.0" + "@sentry/types": "8.33.1", + "@sentry/utils": "8.33.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/types": { - "version": "8.30.0", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.33.1.tgz", + "integrity": "sha512-GjoAMvwtpIemoF/IiwZ7A60g4nQv3qwzR21GvJqDVUoKD0e8pv9OLX+HyXoUat4wEDGSuDUcUyUKD2G+od73QA==", "engines": { "node": ">=14.18" } }, "node_modules/@sentry/utils": { - "version": "8.30.0", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.33.1.tgz", + "integrity": "sha512-uzuYpiiJuFY3N4WNHMBWUQX5oNv2t/TbG0OHRp3Rr7yeu+HSfD542TIp9/gMZ+G0Cxd8AmVO3wkKIFbk0TL4Qg==", "dependencies": { - "@sentry/types": "8.30.0" + "@sentry/types": "8.33.1" }, "engines": { "node": ">=14.18" @@ -6699,6 +6746,8 @@ }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", "dev": true, "license": "MIT" }, @@ -7067,7 +7116,9 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.7", + "version": "4.17.9", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.9.tgz", + "integrity": "sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==", "dev": true, "license": "MIT" }, @@ -7105,7 +7156,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.5.5", + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", "dev": true, "license": "MIT", "dependencies": { @@ -7181,12 +7234,16 @@ "license": "MIT" }, "node_modules/@types/rbush": { - "version": "3.0.4", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/rbush/-/rbush-3.0.3.tgz", + "integrity": "sha512-lX55lR0iYCgapxD3IrgujpQA1zDxwZI5qMRelKvmKAsSMplFVr7wmMpG7/6+Op2tjrgEex8o3vjg8CRDrRNYxg==", "dev": true, "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.5", + "version": "18.3.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz", + "integrity": "sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -7336,7 +7393,9 @@ "license": "MIT" }, "node_modules/@types/validator": { - "version": "13.12.1", + "version": "13.12.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz", + "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==", "dev": true, "license": "MIT" }, @@ -7419,6 +7478,8 @@ }, "node_modules/@types/yauzl": { "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "dev": true, "license": "MIT", "optional": true, @@ -7427,17 +7488,18 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz", - "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz", + "integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.6.0", - "@typescript-eslint/type-utils": "8.6.0", - "@typescript-eslint/utils": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/type-utils": "8.7.0", + "@typescript-eslint/utils": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -7460,15 +7522,35 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz", - "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz", + "integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.6.0", - "@typescript-eslint/utils": "8.6.0", + "@typescript-eslint/typescript-estree": "8.7.0", + "@typescript-eslint/utils": "8.7.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -7485,6 +7567,94 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", + "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", + "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/experimental-utils": { "version": "4.33.0", "dev": true, @@ -7615,16 +7785,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz", - "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz", + "integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.6.0", - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/typescript-estree": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", "debug": "^4.3.4" }, "engines": { @@ -7643,12 +7814,96 @@ } } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", + "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz", "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/types": "8.6.0", "@typescript-eslint/visitor-keys": "8.6.0" @@ -7808,6 +8063,7 @@ "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7822,6 +8078,7 @@ "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/types": "8.6.0", "@typescript-eslint/visitor-keys": "8.6.0", @@ -7851,6 +8108,7 @@ "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.6.0", @@ -7874,6 +8132,7 @@ "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/types": "8.6.0", "eslint-visitor-keys": "^3.4.3" @@ -8990,6 +9249,8 @@ }, "node_modules/ast-types": { "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", "dev": true, "license": "MIT", "dependencies": { @@ -9573,6 +9834,8 @@ }, "node_modules/bare-fs": { "version": "2.3.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", + "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -9584,12 +9847,16 @@ }, "node_modules/bare-os": { "version": "2.4.4", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", + "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", "dev": true, "license": "Apache-2.0", "optional": true }, "node_modules/bare-path": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -9599,6 +9866,8 @@ }, "node_modules/bare-stream": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.0.tgz", + "integrity": "sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -9670,6 +9939,8 @@ }, "node_modules/basic-ftp": { "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "dev": true, "license": "MIT", "engines": { @@ -10652,6 +10923,8 @@ }, "node_modules/chromium-bidi": { "version": "0.6.5", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.5.tgz", + "integrity": "sha512-RuLrmzYrxSb0s9SgpB+QN5jJucPduZQ/9SIe76MDxYJuecPW5mxMdacJ1f4EtgiV+R0p3sCkznTMvH0MPGFqjA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -20132,6 +20405,8 @@ }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "dev": true, "license": "MIT", "engines": { @@ -20224,7 +20499,9 @@ } }, "node_modules/date-fns": { - "version": "3.6.0", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", "devOptional": true, "license": "MIT", "funding": { @@ -20456,6 +20733,8 @@ }, "node_modules/degenerator": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -20692,7 +20971,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1330662", + "version": "0.0.1342118", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", + "integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==", "dev": true, "license": "BSD-3-Clause" }, @@ -23263,6 +23544,8 @@ }, "node_modules/extract-zip": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -23282,6 +23565,8 @@ }, "node_modules/extract-zip/node_modules/get-stream": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "license": "MIT", "dependencies": { @@ -23377,6 +23662,8 @@ }, "node_modules/fd-slicer": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "license": "MIT", "dependencies": { @@ -24623,6 +24910,8 @@ }, "node_modules/get-uri": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dev": true, "license": "MIT", "dependencies": { @@ -24637,6 +24926,8 @@ }, "node_modules/get-uri/node_modules/fs-extra": { "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, "license": "MIT", "dependencies": { @@ -30903,6 +31194,8 @@ }, "node_modules/mitt": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "dev": true, "license": "MIT" }, @@ -31630,6 +31923,8 @@ }, "node_modules/netmask": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", "dev": true, "license": "MIT", "engines": { @@ -32128,40 +32423,6 @@ } } }, - "node_modules/nx/node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.7.3", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.7.3.tgz", - "integrity": "sha512-YMb4WGGovwgxsP6VvAEnyWvLoUwsDrdE5CxFQ2yoThD2BixmSHUKLtx6dtPDHz25nOE3v1ZzM0xTwYXBhPaeRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/nx/node_modules/@nx/nx-win32-x64-msvc": { - "version": "19.7.3", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.7.3.tgz", - "integrity": "sha512-ULNf73gLgB5cU/O4dlQe6tetbRIROTmaUNYTUUCCAC0BqVwZwPDxn4u9C5LgiErVyfPwwAhlserCGei5taLASQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/nx/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, @@ -32548,11 +32809,13 @@ "license": "MIT" }, "node_modules/ol": { - "version": "10.1.0", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/ol/-/ol-10.2.1.tgz", + "integrity": "sha512-2bB/y2vEnmzjqynP0NA7Cp8k86No3Psn63Dueicep3E3i09axWRVIG5IS/bylEAGfWQx0QXD/uljkyFoY60Wig==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@types/rbush": "^3.0.3", + "@types/rbush": "3.0.3", "color-rgba": "^3.0.0", "color-space": "^2.0.1", "earcut": "^3.0.0", @@ -32915,6 +33178,8 @@ }, "node_modules/pac-proxy-agent": { "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", "dev": true, "license": "MIT", "dependencies": { @@ -32933,6 +33198,8 @@ }, "node_modules/pac-resolver": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, "license": "MIT", "dependencies": { @@ -33373,6 +33640,8 @@ }, "node_modules/pend": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true, "license": "MIT" }, @@ -35253,6 +35522,8 @@ }, "node_modules/proxy-agent": { "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dev": true, "license": "MIT", "dependencies": { @@ -35271,6 +35542,8 @@ }, "node_modules/proxy-agent/node_modules/lru-cache": { "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, "license": "ISC", "engines": { @@ -35350,7 +35623,9 @@ } }, "node_modules/puppeteer": { - "version": "23.3.0", + "version": "23.4.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.4.1.tgz", + "integrity": "sha512-+wWfWTkQ8L9IB/3OVGSUp37c0eQ5za/85KdX+LAq2wTZkMdocgYGMCs+/91e2f/RXIYzve4x/uGxN8zG2sj8+w==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -35358,8 +35633,8 @@ "@puppeteer/browsers": "2.4.0", "chromium-bidi": "0.6.5", "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1330662", - "puppeteer-core": "23.3.0", + "devtools-protocol": "0.0.1342118", + "puppeteer-core": "23.4.1", "typed-query-selector": "^2.12.0" }, "bin": { @@ -35370,14 +35645,16 @@ } }, "node_modules/puppeteer-core": { - "version": "23.3.0", + "version": "23.4.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.4.1.tgz", + "integrity": "sha512-uCxGtn8VE9PlKhdFJX/zZySi9K3Ufr3qUZe28jxJoZUqiMJOi+SFh2zhiFDSjWqZIDkc0FtnaCC+rewW3MYXmg==", "dev": true, "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.4.0", "chromium-bidi": "0.6.5", - "debug": "^4.3.6", - "devtools-protocol": "0.0.1330662", + "debug": "^4.3.7", + "devtools-protocol": "0.0.1342118", "typed-query-selector": "^2.12.0", "ws": "^8.18.0" }, @@ -41162,6 +41439,8 @@ }, "node_modules/tar-fs": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", "dev": true, "license": "MIT", "dependencies": { @@ -41712,6 +41991,7 @@ "version": "1.3.0", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=16" }, @@ -42239,6 +42519,8 @@ }, "node_modules/typed-query-selector": { "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", "dev": true, "license": "MIT" }, @@ -42294,6 +42576,97 @@ } } }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz", + "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/type-utils": "8.6.0", + "@typescript-eslint/utils": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz", + "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz", + "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/utils": "8.6.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/uglify-js": { "version": "3.19.2", "dev": true, @@ -42332,6 +42705,8 @@ }, "node_modules/unbzip2-stream": { "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dev": true, "license": "MIT", "dependencies": { @@ -42341,6 +42716,8 @@ }, "node_modules/unbzip2-stream/node_modules/buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ { @@ -42790,6 +43167,8 @@ }, "node_modules/urlpattern-polyfill": { "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", "dev": true, "license": "MIT" }, @@ -44557,6 +44936,8 @@ }, "node_modules/yauzl": { "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "license": "MIT", "dependencies": { @@ -44566,6 +44947,8 @@ }, "node_modules/yauzl/node_modules/buffer-crc32": { "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "license": "MIT", "engines": { @@ -44605,6 +44988,8 @@ }, "node_modules/zod": { "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "dev": true, "license": "MIT", "funding": { @@ -44635,10 +45020,11 @@ }, "packages/admin": { "name": "iobroker.admin", - "version": "7.1.5", + "version": "7.2.0", "license": "MIT", "dependencies": { - "@iobroker/adapter-core": "^3.1.6", + "@iobroker/adapter-core": "^3.2.1", + "@iobroker/i18n": "^0.2.2", "@iobroker/socket-classes": "^1.5.6", "@iobroker/webserver": "^1.0.6", "@iobroker/ws-server": "^2.1.2", @@ -44668,13 +45054,27 @@ } }, "packages/admin/node_modules/@iobroker/adapter-core": { - "version": "3.1.6", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@iobroker/adapter-core/-/adapter-core-3.2.1.tgz", + "integrity": "sha512-sUvNZV5sUvg8TcucJ+CLDYgZ0sSivQEmkIaJQHNPU8yUBzOU//ECCc55gz+B2BVvgeGIN3fnmlCS9hOu7yOulw==", "license": "MIT", "engines": { - "npm": ">=7.0.0" + "node": ">=16" }, "peerDependencies": { - "@iobroker/types": "^6.0.0" + "@iobroker/types": "^6.0.11" + } + }, + "packages/admin/node_modules/@iobroker/i18n": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@iobroker/i18n/-/i18n-0.2.1.tgz", + "integrity": "sha512-lJtiuaCSgicvJrvCzd0JMfY+zBtd4PDArv/EH/v6QuuTKRt3BU+dAQFWOQ35D8/47TKDH8IXKBKFjMglUwB//w==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@iobroker/types": "^7.0.0-alpha.1-20241001-61327866b" } }, "packages/admin/node_modules/@iobroker/socket-classes": { @@ -44942,18 +45342,18 @@ }, "packages/dm-gui-components": { "name": "@iobroker/dm-gui-components", - "version": "7.1.5", + "version": "7.2.0", "license": "MIT", "dependencies": { - "@iobroker/adapter-react-v5": "^7.1.4", + "@iobroker/adapter-react-v5": "^7.2.1", "@iobroker/json-config": "file:../jsonConfig" } }, "packages/jsonConfig": { "name": "@iobroker/json-config", - "version": "7.1.5", + "version": "7.2.0", "dependencies": { - "@iobroker/adapter-react-v5": "^7.1.4", + "@iobroker/adapter-react-v5": "^7.2.1", "crypto-js": "^4.2.0", "react-ace": "^12.0.0" } diff --git a/package.json b/package.json index 4aec9601b..5d0b87115 100644 --- a/package.json +++ b/package.json @@ -28,25 +28,25 @@ "@dilesoft/vite-plugin-federation-dynamic": "^1.1.9", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@fnando/sparkline": "^0.3.10", - "@foxriver76/iob-component-lib": "^0.1.5", + "@foxriver76/iob-component-lib": "^0.1.6", "@honkhonk/vite-plugin-svgr": "^1.1.0", - "@iobroker/adapter-react-v5": "^7.1.4", + "@iobroker/adapter-react-v5": "^7.2.1", "@iobroker/admin-component-easy-access": "^1.0.1", - "@iobroker/build-tools": "^1.0.2", + "@iobroker/build-tools": "^1.1.0", "@iobroker/dm-utils": "^0.5.0", - "@iobroker/eslint-config": "^0.1.5", + "@iobroker/eslint-config": "^0.1.6", "@iobroker/js-controller-common-db": "^6.0.12-alpha.0-20240913-9a3639aed", "@iobroker/legacy-testing": "^1.0.13", - "@iobroker/socket-client": "^3.0.1", + "@iobroker/socket-client": "^3.1.0", "@iobroker/testing": "^5.0.0", - "@iobroker/types": "^6.0.12-alpha.0-20240913-9a3639aed", - "@mui/icons-material": "^6.1.0", - "@mui/material": "^6.1.0", - "@mui/x-data-grid": "^7.17.0", - "@mui/x-date-pickers": "^7.17.0", + "@iobroker/types": "^7.0.0-alpha.1-20241001-61327866b", + "@mui/icons-material": "^6.1.1", + "@mui/material": "^6.1.1", + "@mui/x-data-grid": "^7.18.0", + "@mui/x-date-pickers": "^7.18.0", "@originjs/vite-plugin-commonjs": "^1.0.3", "@react-leaflet/core": "^2.1.0", - "@sentry/browser": "^8.30.0", + "@sentry/browser": "^8.33.1", "@testing-library/jest-dom": "^6.5.0", "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.5.2", @@ -62,15 +62,15 @@ "@types/express-session": "^1.18.0", "@types/leaflet": "^1.9.12", "@types/less": "^3.0.6", - "@types/lodash": "^4.17.7", + "@types/lodash": "^4.17.9", "@types/mocha": "^10.0.8", - "@types/node": "^22.5.5", + "@types/node": "^22.7.4", "@types/passport": "^1.0.16", "@types/passport-local": "^1.0.38", - "@types/react": "^18.3.5", + "@types/react": "^18.3.10", "@types/react-color": "^3.0.12", "@types/react-dom": "^18.3.0", - "@types/validator": "^13.12.1", + "@types/validator": "^13.12.2", "babel": "^6.23.0", "babel-plugin-inline-json-import": "^0.3.2", "buffer": "^6.0.3", @@ -82,7 +82,7 @@ "cron-parser": "^4.9.0", "cronstrue": "^2.50.0", "crypto-js": "^4.2.0", - "date-fns": "^3.6.0", + "date-fns": "^4.1.0", "echarts": "^5.5.1", "echarts-for-react": "^3.0.2", "globals": "^15.9.0", @@ -96,10 +96,10 @@ "lodash": "^4.17.21", "mocha": "^10.7.3", "moment": "^2.30.1", - "ol": "^10.1.0", + "ol": "^10.2.1", "prettier": "^3.3.3", "prop-types": "^15.8.1", - "puppeteer": "^23.3.0", + "puppeteer": "^23.4.1", "react": "^18.3.1", "react-ace": "^12.0.0", "react-color": "^2.19.3", @@ -128,10 +128,10 @@ "typescript": "^5.6.2" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.7.3", - "@nx/nx-darwin-x64": "19.7.3", - "@nx/nx-linux-x64-gnu": "19.7.4", - "@nx/nx-win32-x64-msvc": "19.7.4" + "@nx/nx-darwin-arm64": "19.8.2", + "@nx/nx-darwin-x64": "19.8.2", + "@nx/nx-linux-x64-gnu": "19.8.2", + "@nx/nx-win32-x64-msvc": "19.8.2" }, "overrides": { "react-sortable-hoc": { @@ -142,10 +142,10 @@ "string-width": "4.2.3", "strip-ansi": "6.0.1", "wrap-ansi": "7.0.0", - "@nx/nx-darwin-arm64": "19.7.3", - "@nx/nx-darwin-x64": "19.7.3", - "@nx/nx-linux-x64-gnu": "19.7.3", - "@nx/nx-win32-x64-msvc": "19.7.3" + "@nx/nx-darwin-arm64": "19.8.2", + "@nx/nx-darwin-x64": "19.8.2", + "@nx/nx-linux-x64-gnu": "19.8.2", + "@nx/nx-win32-x64-msvc": "19.8.2" } }, "scripts": { diff --git a/packages/admin/eslint.config.mjs b/packages/admin/eslint.config.mjs index 997aed169..a09161504 100644 --- a/packages/admin/eslint.config.mjs +++ b/packages/admin/eslint.config.mjs @@ -18,7 +18,7 @@ export default [ // disable temporary the rule 'jsdoc/require-param' and enable 'jsdoc/require-jsdoc' rules: { 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-param': 'off' - } - } + 'jsdoc/require-param': 'off', + }, + }, ]; diff --git a/packages/admin/io-package.json b/packages/admin/io-package.json index 34a7f0877..0176d6cbd 100644 --- a/packages/admin/io-package.json +++ b/packages/admin/io-package.json @@ -1,7 +1,7 @@ { "common": { "name": "admin", - "version": "7.1.5", + "version": "7.2.0", "titleLang": { "en": "Admin", "de": "Admin", @@ -19,6 +19,19 @@ "connectionType": "local", "dataSource": "push", "news": { + "7.2.0": { + "en": "Added the check of well-known passwords for the linux systems\nAdded the history for the installation from URL\nfixed wrongly displayed repository warning", + "de": "Hinzugefügt die Überprüfung der bekannten Passwörter für die Linux-Systeme\nDie Geschichte der Installation von URL hinzugefügt\nfalsch angezeigte repository-warnung", + "ru": "Добавлена проверка известных паролей для систем linux\nДобавлена история установки из URL\nнеправильное предупреждение о репозитории", + "pt": "Adicionado a verificação de senhas bem conhecidas para os sistemas linux\nAdicionado o histórico para a instalação de URL\naviso de repositório exibido incorretamente", + "nl": "De controle van bekende wachtwoorden voor de Linux systemen toegevoegd\nDe geschiedenis voor de installatie van URL toegevoegd\nvaste foutief weergegeven repository waarschuwing", + "fr": "Ajout de la vérification des mots de passe connus pour les systèmes linux\nAjout de l'historique de l'installation depuis l'URL\ncorrection de l'avertissement du dépôt affiché à tort", + "it": "Aggiunto il controllo delle password ben note per i sistemi linux\nAggiunto la storia per l'installazione da URL\nfisso erroneamente visualizzato avviso di repository", + "es": "Agregó el cheque de contraseñas conocidas para los sistemas linux\nAñadido la historia para la instalación desde URL\naviso de repositorio mal mostrado", + "pl": "Dodano sprawdzanie dobrze znanych haseł dla systemów linux\nDodano historię instalacji z URL\nnieprawidłowo ustawione ostrzeżenie repozytorium", + "uk": "Додано перевірку відомих паролів для Linux\nДодано історію установки з URL\nвиправлено неправильно відображається попередження репозиторій", + "zh-cn": "添加了对 Linux 系统的著名密码的检查\n从 URL 添加安装历史\n错误显示仓库警告" + }, "7.1.5": { "en": "Added the read-only flag to the `state` JSON Config component", "de": "Die Nur-Lese-Flagge zur \"state\" hinzugefügt JSON Config Komponente", @@ -96,19 +109,6 @@ "pl": "Poprawa w przypadku badań automatycznych\nDodano możliwość stylizacji tekstu odpowiedzi dla 'textSendTo' w konfiguracji JSON", "uk": "Покращення автоматичних випробувань\nДодано можливість стилю тексту відповіді для `textSendTo`` в JSON Config", "zh-cn": "改进自动测试\n在 JSON 配置中添加了“ textSendTo” 的响应文本样式" - }, - "7.0.24": { - "en": "Showed min/max limits by controlling the values\nCorrected style for tabs", - "de": "Gezeigte Min/Max-Grenzwerte durch Steuerung der Werte\nKorrigierter Stil für Tabs", - "ru": "Показано ограничение min/max, контролируя значения\nИсправленный стиль для вкладок", - "pt": "Mostrado limites min/max controlando os valores\nEstilo corrigido para abas", - "nl": "Min/max limieten getoond door de waarden te controleren\nGecorrigeerde stijl voor tabbladen", - "fr": "Limites min/max indiquées en contrôlant les valeurs\nStyle corrigé pour les onglets", - "it": "Mostrati limiti min/max controllando i valori\nStile corretto per schede", - "es": "Visualizado min/max límites controlando los valores\nEstilo corregido para pestañas", - "pl": "Pokazane wartości graniczne min / max poprzez kontrolę wartości\nPoprawiony styl dla zakładek", - "uk": "Виявлені ліміти хв/максів, які контролюють значення\nПравильний стиль для вкладок", - "zh-cn": "通过控制值来显示分钟/最大限制\n校正标签样式" } }, "desc": { @@ -411,6 +411,38 @@ }, "regex": [], "limit": 10 + }, + { + "category": "wellKnownPassword", + "name": { + "en": "Well known password", + "de": "Bekanntes Passwort", + "ru": "Известный пароль", + "pt": "Senha bem conhecida", + "nl": "Bekend wachtwoord", + "fr": "Mot de passe bien connu", + "it": "Password ben nota", + "es": "Contraseña bien conocida", + "pl": "Znane hasło", + "uk": "Відомий пароль", + "zh-cn": "众所周知的密码" + }, + "severity": "alert", + "description": { + "en": "Your Linux system uses a user with a well-known password. This can lead to the system being hacked from the outside. It is strongly recommended to change the password.", + "de": "Ihr Linux-System verwendet einen Benutzer mit einem bekannten Passwort. Dies kann dazu führen, dass das System von außen gehackt wird. Es wird dringend empfohlen, das Passwort zu ändern.", + "ru": "Ваша Linux система использует пользователя с хорошо известным паролем. Это может стать причиной взлома системы извне. Настоятельно рекомендуется сменить пароль.", + "pt": "Seu sistema Linux usa um usuário com uma senha bem conhecida. Isso pode levar ao hackeamento do sistema de fora. É altamente recomendável mudar a senha.", + "nl": "Uw Linux-systeem gebruikt een gebruiker met een bekend wachtwoord. Dit kan ertoe leiden dat het systeem van buitenaf wordt gehackt. Het wordt sterk aanbevolen om het wachtwoord te wijzigen.", + "fr": "Votre système Linux utilise un utilisateur avec un mot de passe bien connu. Cela peut entraîner le piratage du système de l'extérieur. Il est fortement recommandé de changer le mot de passe.", + "it": "Il tuo sistema Linux utilizza un utente con una password ben nota. Questo può portare a un attacco al sistema dall'esterno. Si consiglia vivamente di cambiare la password.", + "es": "Su sistema Linux utiliza un usuario con una contraseña bien conocida. Esto puede llevar a que el sistema sea hackeado desde el exterior. Se recomienda encarecidamente cambiar la contraseña.", + "pl": "Twój system Linux używa użytkownika ze znanym hasłem. Może to prowadzić do włamania do systemu z zewnątrz. Zaleca się zmianę hasła.", + "uk": "Ваша Linux система використовує користувача з добре відомим паролем. Це може призвести до злому системи ззовні. Настійно рекомендується змінити пароль.", + "zh-cn": "您的 Linux 系统使用众所周知的密码。 这可能导致系统被外部黑客攻击。 强烈建议更改密码。" + }, + "regex": [], + "limit": 1 } ] } diff --git a/packages/admin/package.json b/packages/admin/package.json index a0dc8741b..ed82feccf 100644 --- a/packages/admin/package.json +++ b/packages/admin/package.json @@ -1,7 +1,7 @@ { "name": "iobroker.admin", "description": "The adapter opens a webserver for the ioBroker admin UI.", - "version": "7.1.5", + "version": "7.2.0", "contributors": [ "bluefox ", "apollon77", @@ -23,7 +23,8 @@ "setup" ], "dependencies": { - "@iobroker/adapter-core": "^3.1.6", + "@iobroker/adapter-core": "^3.2.1", + "@iobroker/i18n": "^0.2.2", "@iobroker/socket-classes": "^1.5.6", "@iobroker/webserver": "^1.0.6", "@iobroker/ws-server": "^2.1.2", diff --git a/packages/admin/src-admin/eslint.config.mjs b/packages/admin/src-admin/eslint.config.mjs index 108a6d429..4ff521c1b 100644 --- a/packages/admin/src-admin/eslint.config.mjs +++ b/packages/admin/src-admin/eslint.config.mjs @@ -24,7 +24,7 @@ export default [ // disable temporary the rule 'jsdoc/require-param' and enable 'jsdoc/require-jsdoc' rules: { 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-param': 'off' - } - } + 'jsdoc/require-param': 'off', + }, + }, ]; diff --git a/packages/admin/src-admin/package.json b/packages/admin/src-admin/package.json index 26784f5eb..815f6c1ba 100644 --- a/packages/admin/src-admin/package.json +++ b/packages/admin/src-admin/package.json @@ -4,11 +4,8 @@ "homepage": ".", "scripts": { "start": "set DANGEROUSLY_DISABLE_HOST_CHECK=true && craco start", - "old-start": "react-scripts start", "lint": "eslint -c eslint.config.mjs src", "build": "craco build", - "test": "react-scripts test", - "eject": "react-scripts eject", "check-ts": "tsc --noEmit --checkJS false", "tsc": "tsc --project tsconfig.json", "prettier": "prettier --write src/**/*.{ts,tsx,js,jsx,json,css,scss,md,html}" @@ -44,4 +41,4 @@ ] ], "version": "7.1.5" -} \ No newline at end of file +} diff --git a/packages/admin/src-admin/src/AdminUtils.tsx b/packages/admin/src-admin/src/AdminUtils.tsx deleted file mode 100644 index 97fbfcfef..000000000 --- a/packages/admin/src-admin/src/AdminUtils.tsx +++ /dev/null @@ -1,828 +0,0 @@ -import semver from 'semver'; -import { type Translate } from '@iobroker/adapter-react-v5'; - -declare module '@mui/material/Button' { - interface ButtonPropsColorOverrides { - grey: true; - } -} - -const ANSI_RESET = 0; -const ANSI_RESET_COLOR = 39; -const ANSI_RESET_BG_COLOR = 49; -const ANSI_BOLD = 1; -const ANSI_RESET_BOLD = 22; - -export interface Style { - color?: string; - backgroundColor?: string; - fontWeight?: string; -} - -const STYLES: Record = { - 30: { color: 'black' }, // ANSI_BLACK - 31: { color: 'red' }, // ANSI_RED - 32: { color: 'green' }, // ANSI_GREEN - 33: { color: 'yellow' }, // ANSI_YELLOW - 34: { color: 'blue' }, // ANSI_BLUE - 35: { color: 'purple' }, // ANSI_PURPLE - 36: { color: 'cyan' }, // ANSI_CYAN - 37: { color: 'white' }, // ANSI_WHITE - - 90: { color: 'grey' }, // ANSI_BRIGHT_BLACK - 91: { color: 'lightred' }, // ANSI_BRIGHT_RED - 92: { color: 'lightgreen' }, // ANSI_BRIGHT_GREEN - 93: { color: 'lightyellow' }, // ANSI_BRIGHT_YELLOW - 94: { color: 'lightblue' }, // ANSI_BRIGHT_BLUE - 95: { color: 'lightpurple' }, // ANSI_BRIGHT_PURPLE - 96: { color: 'lightcyan' }, // ANSI_BRIGHT_CYAN - 97: { color: 'white' }, // ANSI_BRIGHT_WHITE - - 40: { backgroundColor: 'black' }, // ANSI_BG_BLACK - 41: { backgroundColor: 'red' }, // ANSI_BG_RED - 42: { backgroundColor: 'green' }, // ANSI_BG_GREEN - 43: { backgroundColor: 'yellow' }, // ANSI_BG_YELLOW - 44: { backgroundColor: 'blue' }, // ANSI_BG_BLUE - 45: { backgroundColor: 'purple' }, // ANSI_BG_PURPLE - 46: { backgroundColor: 'cyan' }, // ANSI_BG_CYAN - 47: { backgroundColor: 'white' }, // ANSI_BG_WHITE - - 100: { backgroundColor: 'grey' }, // ANSI_BRIGHT_BG_BLACK - 101: { backgroundColor: 'lightred' }, // ANSI_BRIGHT_BG_RED - 102: { backgroundColor: 'lightgreen' }, // ANSI_BRIGHT_BG_GREEN - 103: { backgroundColor: 'lightyellow' }, // ANSI_BRIGHT_BG_YELLOW - 104: { backgroundColor: 'lightblue' }, // ANSI_BRIGHT_BG_BLUE - 105: { backgroundColor: 'lightpurple' }, // ANSI_BRIGHT_BG_PURPLE - 106: { backgroundColor: 'lightcyan' }, // ANSI_BRIGHT_BG_CYAN - 107: { backgroundColor: 'white' }, // ANSI_BRIGHT_BG_WHITE -}; - -class AdminUtils { - /** - * Perform JSON parse/stringify with type inference - * - * @param obj the object to clone - */ - static deepClone>(obj: T): T { - return JSON.parse(JSON.stringify(obj)); - } - - /** - * Format bytes to MB or GB - * - * @param bytes the number of bytes - */ - static formatRam(bytes: number): string { - const GB = Math.floor((bytes / (1024 * 1024 * 1024)) * 10) / 10; - bytes %= 1024 * 1024 * 1024; - const MB = Math.floor((bytes / (1024 * 1024)) * 10) / 10; - let text = ''; - - if (GB > 1) { - text += `${GB} GB`; - } else { - text += `${MB} MB`; - } - - return text; - } - - static formatSpeed(mhz: number): string { - return `${mhz} MHz`; - } - - static formatBytes(bytes: number): string { - if (Math.abs(bytes) < 1024) { - return `${bytes} B`; - } - - const units = ['KB', 'MB', 'GB']; - // const units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']; - let u = -1; - - do { - bytes /= 1024; - ++u; - } while (Math.abs(bytes) >= 1024 && u < units.length - 1); - - return `${bytes.toFixed(1)} ${units[u]}`; - } - - static getFileExtension(fileName: string): string | null { - const pos = fileName.lastIndexOf('.'); - if (pos !== -1) { - return fileName.substring(pos + 1).toLowerCase(); - } - return null; - } - - // Big thanks to: https://stackoverflow.com/questions/35969656/how-can-i-generate-the-opposite-color-according-to-current-color - static invertColor(hex: string, bw: boolean): string { - if (hex === undefined || hex === null || hex === '' || typeof hex !== 'string') { - return ''; - } - if (hex.indexOf('#') === 0) { - hex = hex.slice(1); - } - // convert 3-digit hex to 6-digits. - if (hex.length === 3) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } - if (hex.length !== 6) { - throw new Error('Invalid HEX color.'); - } - const r = parseInt(hex.slice(0, 2), 16); - const g = parseInt(hex.slice(2, 4), 16); - const b = parseInt(hex.slice(4, 6), 16); - - if (bw) { - // http://stackoverflow.com/a/3943023/112731 - return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? '#000000' : '#FFFFFF'; - } - // invert color components - const finalR = (255 - r).toString(16); - const finalG = (255 - g).toString(16); - const finalB = (255 - b).toString(16); - // pad each with zeros and return - return `#${finalR.padStart(2, '0')}${finalG.padStart(2, '0')}${finalB.padStart(2, '0')}`; - } - - /** - * Format number in seconds to time text - * - * @param seconds the number of seconds - * @param t i18n.t function - */ - static formatSeconds(seconds: number, t: Translate): string { - const days = Math.floor(seconds / (3600 * 24)); - let minutesRes: string; - let secondsRes: string; - let hoursRes: string; - - seconds %= 3600 * 24; - const hours = Math.floor(seconds / 3600); - - if (hours < 10) { - hoursRes = `0${hours}`; - } else { - hoursRes = hours.toString(); - } - seconds %= 3600; - const minutes = Math.floor(seconds / 60); - if (minutes < 10) { - minutesRes = `0${minutes}`; - } else { - minutesRes = minutes.toString(); - } - - seconds %= 60; - seconds = Math.floor(seconds); - if (seconds < 10) { - secondsRes = `0${seconds}`; - } else { - secondsRes = seconds.toString(); - } - - let text = ''; - if (days) { - text += `${days} ${t('daysShortText')} `; - } - text += `${hoursRes}:${minutesRes}:${secondsRes}`; - - return text; - } - - // internal use - static _replaceLink( - link: string, - objects: Record, - adapterInstance: string, - attr: string, - placeholder: string, - hosts: Record, - hostname: string, - adminInstance: string, - ): string { - if (attr === 'protocol') { - attr = 'secure'; - } - - try { - const object = objects[`system.adapter.${adapterInstance}`]; - - if (link && object) { - if (attr === 'secure') { - link = link.replace(`%${placeholder}%`, object.native[attr] ? 'https' : 'http'); - } else { - let value = object.native[attr]; - // workaround for port - if ((attr === 'webinterfacePort' || attr === 'port') && (!value || value === '0')) { - if (object.native.secure === true) { - value = 443; - } else { - value = 80; - } - } - - if (attr === 'bind' || attr === 'ip') { - let ip = object.native.bind || object.native.ip; - if (ip === '0.0.0.0') { - ip = AdminUtils.getHostname(object, objects, hosts, hostname, adminInstance); - } - if (!link.includes(`%${placeholder}%`)) { - link = link.replace(`%native_${placeholder}%`, ip || ''); - } else { - link = link.replace(`%${placeholder}%`, ip || ''); - } - } else if (!link.includes(`%${placeholder}%`)) { - link = link.replace(`%native_${placeholder}%`, value); - } else { - link = link.replace(`%${placeholder}%`, value); - } - } - } else { - console.log(`Cannot get link ${attr}`); - link = link.replace(`%${placeholder}%`, ''); - } - } catch (error) { - console.log(error); - } - return link; - } - - static ip2int(ip: string): number { - return ip.split('.').reduce((ipInt, octet) => (ipInt << 8) + parseInt(octet, 10), 0) >>> 0; - } - - static findNetworkAddressOfHost(obj: ioBroker.HostObject, localIp: string): null | string { - const networkInterfaces = obj?.native?.hardware?.networkInterfaces; - if (!networkInterfaces) { - return null; - } - - let hostIp; - for (const networkInterface of Object.values(networkInterfaces)) { - if (!networkInterface) { - continue; - } - for (let i = 0; i < networkInterface.length; i++) { - const ip = networkInterface[i]; - if (ip.internal) { - return; - } - if (localIp.includes(':') && ip.family !== 'IPv6') { - return; - } - if (localIp.includes('.') && !localIp.match(/[^.\d]/) && ip.family !== 'IPv4') { - return; - } - if (localIp === '127.0.0.0' || localIp === 'localhost' || localIp.match(/[^.\d]/)) { - // if DNS name - hostIp = ip.address; - } else if ( - ip.family === 'IPv4' && - localIp.includes('.') && - (AdminUtils.ip2int(localIp) & AdminUtils.ip2int(ip.netmask)) === - (AdminUtils.ip2int(ip.address) & AdminUtils.ip2int(ip.netmask)) - ) { - hostIp = ip.address; - } else { - hostIp = ip.address; - } - } - } - - if (!hostIp) { - for (const networkInterface of Object.values(networkInterfaces)) { - if (!networkInterface) { - continue; - } - for (let i = 0; i < networkInterface.length; i++) { - const ip = networkInterface[i]; - if (ip.internal) { - return; - } - if (localIp.includes(':') && ip.family !== 'IPv6') { - return; - } - if (localIp.includes('.') && !localIp.match(/[^.\d]/) && ip.family !== 'IPv4') { - return; - } - if (localIp === '127.0.0.0' || localIp === 'localhost' || localIp.match(/[^.\d]/)) { - // if DNS name - hostIp = ip.address; - } else { - hostIp = ip.address; - } - } - } - } - - if (!hostIp) { - for (const networkInterface of Object.values(networkInterfaces)) { - if (!networkInterface) { - continue; - } - for (let i = 0; i < networkInterface.length; i++) { - const ip = networkInterface[i]; - if (ip.internal) { - return; - } - hostIp = ip.address; - } - } - } - - return hostIp; - } - - static getHostname( - instanceObj: ioBroker.InstanceObject, - objects: Record, - hosts: Record, - currentHostname: string, - adminInstance: string, - ): string { - if (!instanceObj || !instanceObj.common) { - return null; - } - - let hostname; - // check if the adapter from the same host as admin - const adminHost = objects[`system.adapter.${adminInstance}`]?.common?.host; - if (instanceObj.common.host !== adminHost) { - // find IP address - const host = hosts[`system.host.${instanceObj.common.host}`]; - if (host) { - const ip = AdminUtils.findNetworkAddressOfHost(host, currentHostname); - if (ip) { - hostname = ip; - } else { - console.warn(`Cannot find suitable IP in host ${instanceObj.common.host} for ${instanceObj._id}`); - return null; - } - } else { - console.warn(`Cannot find host ${instanceObj.common.host} for ${instanceObj._id}`); - return null; - } - } else { - hostname = currentHostname; - } - - return hostname; - } - - /** - * Convert the template link to string - */ - static replaceLink( - /** pattern for link */ - link: string, - /** adapter name */ - adapter: string, - /** adapter instance number */ - instance: number, - context: { - instances: Record; - hostname: string; - adminInstance: string; - hosts: Record; - }, - ): { - url: string; - port: number; - instance?: string; - }[] { - const _urls: { - url: string; - port: number; - instance?: string; - }[] = []; - let port: number; - - if (link) { - const instanceObj = context.instances[`system.adapter.${adapter}.${instance}`]; - const native = instanceObj?.native || {}; - - const placeholders = link.match(/%(\w+)%/g); - - if (placeholders) { - for (let p = 0; p < placeholders.length; p++) { - let placeholder = placeholders[p]; - - if (placeholder === '%ip%') { - let ip: string = (native.bind || native.ip) as string; - if (!ip || ip === '127.0.0.1' || ip === 'localhost' || ip === '0.0.0.0') { - // Check host - ip = AdminUtils.getHostname( - instanceObj, - context.instances, - context.hosts, - context.hostname, - context.adminInstance, - ); - } - - if (_urls.length) { - _urls.forEach(item => (item.url = item.url.replace('%ip%', ip))); - } else { - link = link.replace('%ip%', ip || ''); - } - } else if (placeholder === '%protocol%') { - const protocolVal: string | boolean = - native.secure === undefined ? native.protocol : native.secure; - let protocol: 'http' | 'https'; - if (protocolVal === true || protocolVal === 'true') { - protocol = 'https'; - } else if (protocolVal === false || protocolVal === 'false' || !protocolVal) { - protocol = 'http'; - } else { - protocol = protocolVal.toString().replace(/:$/, '') as 'http' | 'https'; - } - - if (_urls.length) { - _urls.forEach(item => (item.url = item.url.replace('%protocol%', protocol))); - } else { - link = link.replace('%protocol%', protocol); - } - } else if (placeholder === '%instance%') { - link = link.replace('%instance%', instance.toString()); - if (_urls.length) { - _urls.forEach(item => (item.url = item.url.replace('%instance%', instance.toString()))); - } else { - link = link.replace('%instance%', instance.toString()); - } - } else { - // remove %% - placeholder = placeholder.replace(/%/g, ''); - - if (placeholder.startsWith('native_')) { - placeholder = placeholder.substring(7); - } - - // like web.0_port or web_protocol - if (!placeholder.includes('_')) { - // if only one instance - const adapterInstance = `${adapter}.${instance}`; - if (_urls.length) { - _urls.forEach( - item => - (item.url = AdminUtils._replaceLink( - item.url, - context.instances, - adapterInstance, - placeholder, - placeholder, - context.hosts, - context.hostname, - context.adminInstance, - )), - ); - } else { - link = AdminUtils._replaceLink( - link, - context.instances, - adapterInstance, - placeholder, - placeholder, - context.hosts, - context.hostname, - context.adminInstance, - ); - port = context.instances[`system.adapter.${adapterInstance}`]?.native?.port; - } - } else { - const [adapterInstance, attr] = placeholder.split('_'); - - // if instance number not found - if (!adapterInstance.match(/\.[0-9]+$/)) { - // list all possible instances - let ids: string[]; - if (adapter === adapterInstance) { - // take only this one instance and that's all - ids = [`${adapter}.${instance}`]; - } else { - ids = Object.keys(context.instances) - .filter( - id => - id.startsWith(`system.adapter.${adapterInstance}.`) && - context.instances[id].common.enabled, - ) - .map(id => id.substring(15)); - - // try to get disabled instances - if (!ids.length) { - ids = Object.keys(context.instances) - .filter(id => id.startsWith(`system.adapter.${adapterInstance}.`)) - .map(id => id.substring(15)); - } - } - - for (const id of ids) { - if (_urls.length) { - const item = _urls.find(t => t.instance === id); - if (item) { - item.url = AdminUtils._replaceLink( - item.url, - context.instances, - id, - attr, - placeholder, - context.hosts, - context.hostname, - context.adminInstance, - ); - } else { - // add new - const _link = AdminUtils._replaceLink( - link, - context.instances, - id, - attr, - placeholder, - context.hosts, - context.hostname, - context.adminInstance, - ); - const _port: number = context.instances[`system.adapter.${id}`]?.native - ?.port as number; - _urls.push({ url: _link, port: _port, instance: id }); - } - } else { - const _link = AdminUtils._replaceLink( - link, - context.instances, - id, - attr, - placeholder, - context.hosts, - context.hostname, - context.adminInstance, - ); - const _port: number = context.instances[`system.adapter.${id}`]?.native - ?.port as number; - _urls.push({ url: _link, port: _port, instance: id }); - } - } - } else { - link = AdminUtils._replaceLink( - link, - context.instances, - adapterInstance, - attr, - placeholder, - context.hosts, - context.hostname, - context.adminInstance, - ); - port = context.instances[`system.adapter.${adapterInstance}`]?.native?.port as number; - } - } - } - } - } - } - - if (_urls.length) { - return _urls; - } - return [{ url: link, port }]; - } - - static objectMap( - object: Record, - callback: (res: Value, key: string) => Result, - ): Result[] { - const result: Result[] = []; - for (const key in object) { - result.push(callback(object[key], key)); - } - return result; - } - - static fixAdminUI(obj: Record): void { - if (obj?.common) { - if (!obj.common.adminUI) { - if (obj.common.noConfig) { - obj.common.adminUI = obj.common.adminUI || {}; - obj.common.adminUI.config = 'none'; - } else if (obj.common.jsonConfig) { - obj.common.adminUI = obj.common.adminUI || {}; - obj.common.adminUI.config = 'json'; - } else if (obj.common.materialize) { - obj.common.adminUI = obj.common.adminUI || {}; - obj.common.adminUI.config = 'materialize'; - } else { - obj.common.adminUI = obj.common.adminUI || {}; - obj.common.adminUI.config = 'html'; - } - - if (obj.common.jsonCustom) { - obj.common.adminUI = obj.common.adminUI || {}; - obj.common.adminUI.custom = 'json'; - } else if (obj.common.supportCustoms) { - obj.common.adminUI = obj.common.adminUI || {}; - obj.common.adminUI.custom = 'json'; - } - - if (obj.common.materializeTab && obj.common.adminTab) { - obj.common.adminUI = obj.common.adminUI || {}; - obj.common.adminUI.tab = 'materialize'; - } else if (obj.common.adminTab) { - obj.common.adminUI = obj.common.adminUI || {}; - obj.common.adminUI.tab = 'html'; - } - - if (obj.common.adminUI) { - console.warn( - `Please add to "${obj._id.replace(/\.\d+$/, '')}" common.adminUI=${JSON.stringify(obj.common.adminUI)}`, - ); - } - } else { - let changed = false; - if (obj.common.materializeTab && obj.common.adminTab) { - if (obj.common.adminUI.tab !== 'materialize') { - obj.common.adminUI.tab = 'materialize'; - changed = true; - } - } else if (obj.common.adminTab) { - if (obj.common.adminUI.tab !== 'html' && obj.common.adminUI.tab !== 'materialize') { - obj.common.adminUI.tab = 'html'; - changed = true; - } - } - - if (obj.common.jsonCustom || obj.common.supportCustoms) { - if (obj.common.adminUI.custom !== 'json') { - obj.common.adminUI.custom = 'json'; - changed = true; - } - } - - if (obj.common.noConfig) { - if (obj.common.adminUI.config !== 'none') { - obj.common.adminUI.config = 'none'; - changed = true; - } - } else if (obj.common.jsonConfig) { - if (obj.common.adminUI.config !== 'json') { - obj.common.adminUI.config = 'json'; - changed = true; - } - obj.common.adminUI.config = 'json'; - } else if (obj.common.materialize) { - if (obj.common.adminUI.config !== 'materialize') { - if (!obj.common.adminUI.config) { - obj.common.adminUI.config = 'materialize'; - changed = true; - } - } - } else if (!obj.common.adminUI.config) { - obj.common.adminUI.config = 'html'; - changed = true; - } - if (changed) { - console.warn( - `Please modify "${obj._id.replace(/\.\d+$/, '')}" common.adminUI=${JSON.stringify(obj.common.adminUI)}`, - ); - } - } - } - } - - static parseColorMessage(text: string): string | { original: string; parts: { text: string; style: Style }[] } { - if (text && (text.includes('\u001b[') || text.includes('\u001B['))) { - // eslint-disable-next-line - let m = text.match(/\u001b\[\d+m/gi); - if (m) { - const original = text; - const result = []; - let style: Style = {}; - for (let i = 0; i < m.length; i++) { - const pos = text.indexOf(m[i]); - if (pos) { - result.push({ text: text.substring(0, pos), style: { ...style } }); - } - const code = parseInt(m[i].substring(2), 10); - if (STYLES[code]) { - Object.assign(style, STYLES[code]); - } else if (ANSI_RESET_COLOR === code) { - delete style.color; - } else if (ANSI_RESET_BG_COLOR === code) { - delete style.backgroundColor; - } else if (ANSI_RESET_BOLD === code) { - delete style.fontWeight; - } else if (ANSI_BOLD === code) { - style.fontWeight = 'bold'; - } else if (ANSI_RESET === code) { - style = {}; - } - text = text.substring(m[i].length + pos); - } - if (text) { - result.push({ text, style: { ...style } }); - } - - return { original, parts: result }; - } - return text; - } - return text; - } - - static PASSWORD_ERROR_LENGTH = - 'Password must be at least 8 characters long and have numbers, upper and lower case letters'; - - static PASSWORD_ERROR_NOT_EQUAL = 'Repeat password is not equal with password'; - - static PASSWORD_ERROR_EMPTY = 'Empty password is not allowed'; - - static PASSWORD_SET = '***********'; - - /** The languages for which docs are generated */ - static SUPPORTED_DOC_LANGUAGES: ioBroker.Languages[] = ['en', 'de', 'ru', 'zh-cn']; - - static checkPassword(password: string, passwordRepeat?: string): false | string { - password = password || ''; - passwordRepeat = passwordRepeat || ''; - if ( - password && - passwordRepeat && - password !== AdminUtils.PASSWORD_SET && - passwordRepeat !== AdminUtils.PASSWORD_SET - ) { - if (password.length < 8 || !password.match(/\d/) || !password.match(/[a-z]/) || !password.match(/[A-Z]/)) { - return AdminUtils.PASSWORD_ERROR_LENGTH; - } - if (password !== passwordRepeat) { - return AdminUtils.PASSWORD_ERROR_NOT_EQUAL; - } - return false; - } - if (password && password !== AdminUtils.PASSWORD_SET) { - if (password.length < 8 || !password.match(/\d/) || !password.match(/[a-z]/) || !password.match(/[A-Z]/)) { - return AdminUtils.PASSWORD_ERROR_LENGTH; - } - return false; - } - if (passwordRepeat && passwordRepeat !== AdminUtils.PASSWORD_SET) { - if ( - passwordRepeat.length < 8 || - !passwordRepeat.match(/\d/) || - !passwordRepeat.match(/[a-z]/) || - !passwordRepeat.match(/[A-Z]/) - ) { - return AdminUtils.PASSWORD_ERROR_LENGTH; - } - return false; - } - if (password === AdminUtils.PASSWORD_SET || passwordRepeat === AdminUtils.PASSWORD_SET) { - return false; - } - return AdminUtils.PASSWORD_ERROR_EMPTY; - } - - /** - * Get Link to adapter docs in given language - * - * @param options the adapter name without ioBroker. prefix and the language information - * @param options.adapterName the adapter name without ioBroker. prefix - * @param options.lang the language for the docs - */ - static getDocsLinkForAdapter(options: { lang: ioBroker.Languages; adapterName: string }): string { - const { adapterName } = options; - let { lang } = options; - - if (!AdminUtils.SUPPORTED_DOC_LANGUAGES.includes(lang)) { - lang = 'en'; - } - - return `https://www.iobroker.net/#${lang}/adapters/adapterref/iobroker.${adapterName}/README.md`; - } - - static updateAvailable(oldVersion: string, newVersion: string): boolean { - try { - return semver.gt(newVersion, oldVersion) === true; - } catch { - console.warn(`[ADAPTERS] Cannot compare "${newVersion}" and "${oldVersion}"`); - return false; - } - } - - static getText(word: ioBroker.StringOrTranslated, lang: ioBroker.Languages): string { - if (typeof word === 'object') { - if (!word) { - return ''; - } - return (word[lang] || word.en || '').toString(); - } - - return word ? word.toString() : ''; - } - - static clone(obj: T): T { - return JSON.parse(JSON.stringify(obj)); - } -} - -export default AdminUtils; diff --git a/packages/admin/src-admin/src/Workers/AdaptersWorker.tsx b/packages/admin/src-admin/src/Workers/AdaptersWorker.tsx index 83c0cbb09..7d1d54e73 100644 --- a/packages/admin/src-admin/src/Workers/AdaptersWorker.tsx +++ b/packages/admin/src-admin/src/Workers/AdaptersWorker.tsx @@ -1,5 +1,5 @@ import { type AdminConnection } from '@iobroker/adapter-react-v5'; -import AdminUtils from '../AdminUtils'; +import AdminUtils from '../helpers/AdminUtils'; export type AdapterEventType = 'new' | 'changed' | 'deleted'; diff --git a/packages/admin/src-admin/src/Workers/InstancesWorker.tsx b/packages/admin/src-admin/src/Workers/InstancesWorker.tsx index c46cc0977..39df0abe9 100644 --- a/packages/admin/src-admin/src/Workers/InstancesWorker.tsx +++ b/packages/admin/src-admin/src/Workers/InstancesWorker.tsx @@ -1,5 +1,5 @@ import { type AdminConnection } from '@iobroker/adapter-react-v5'; -import AdminUtils from '../AdminUtils'; +import AdminUtils from '../helpers/AdminUtils'; export type InstanceEventType = 'new' | 'changed' | 'deleted'; diff --git a/packages/admin/src-admin/src/Workers/LogsWorker.tsx b/packages/admin/src-admin/src/Workers/LogsWorker.tsx index 65744d1f0..3a5ec17b2 100644 --- a/packages/admin/src-admin/src/Workers/LogsWorker.tsx +++ b/packages/admin/src-admin/src/Workers/LogsWorker.tsx @@ -1,5 +1,5 @@ import { type AdminConnection } from '@iobroker/adapter-react-v5'; -import AdminUtils, { type Style } from '../AdminUtils'; +import AdminUtils, { type Style } from '../helpers/AdminUtils'; interface LogLine { severity: string; diff --git a/packages/admin/src-admin/src/Workers/ObjectsWorker.tsx b/packages/admin/src-admin/src/Workers/ObjectsWorker.tsx index f40444cd5..952e9b257 100644 --- a/packages/admin/src-admin/src/Workers/ObjectsWorker.tsx +++ b/packages/admin/src-admin/src/Workers/ObjectsWorker.tsx @@ -1,5 +1,5 @@ import { type AdminConnection } from '@iobroker/adapter-react-v5'; -import AdminUtils from '../AdminUtils'; +import AdminUtils from '../helpers/AdminUtils'; export type ObjectEventType = 'new' | 'changed' | 'deleted'; diff --git a/packages/admin/src-admin/src/components/Adapters/AdapterGeneric.tsx b/packages/admin/src-admin/src/components/Adapters/AdapterGeneric.tsx index 6df61a70f..c5ef3dd89 100644 --- a/packages/admin/src-admin/src/components/Adapters/AdapterGeneric.tsx +++ b/packages/admin/src-admin/src/components/Adapters/AdapterGeneric.tsx @@ -45,7 +45,7 @@ import AdapterUpdateDialog from '@/dialogs/AdapterUpdateDialog'; import CustomModal from '@/components/CustomModal'; import RatingDialog, { type RatingDialogRepository } from '@/dialogs/RatingDialog'; import AdapterDeletionDialog from '@/dialogs/AdapterDeletionDialog'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import AdapterInstallDialog, { type AdapterInstallDialogState, type AdapterRating, diff --git a/packages/admin/src-admin/src/components/Command.tsx b/packages/admin/src-admin/src/components/Command.tsx index 2019bb903..a7f53725a 100644 --- a/packages/admin/src-admin/src/components/Command.tsx +++ b/packages/admin/src-admin/src/components/Command.tsx @@ -6,7 +6,7 @@ import { Grid2, LinearProgress, Paper, Switch, Typography } from '@mui/material' import { Router, type AdminConnection, type Translate } from '@iobroker/adapter-react-v5'; -import AdminUtils, { type Style } from '../AdminUtils'; +import AdminUtils, { type Style } from '../helpers/AdminUtils'; const styles: Record = { log: { diff --git a/packages/admin/src-admin/src/components/ContextWrapper.tsx b/packages/admin/src-admin/src/components/ContextWrapper.tsx index b084da73b..1e0b67000 100644 --- a/packages/admin/src-admin/src/components/ContextWrapper.tsx +++ b/packages/admin/src-admin/src/components/ContextWrapper.tsx @@ -1,6 +1,6 @@ import React, { createContext, useEffect, useMemo, useState, type JSX } from 'react'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; type MyContext = { hostsUpdate: number; diff --git a/packages/admin/src-admin/src/components/Drawer.tsx b/packages/admin/src-admin/src/components/Drawer.tsx index b7e321fa4..8a0914531 100644 --- a/packages/admin/src-admin/src/components/Drawer.tsx +++ b/packages/admin/src-admin/src/components/Drawer.tsx @@ -32,7 +32,7 @@ import { } from '@iobroker/adapter-react-v5'; import { getHref } from '@/tabs/CustomTab'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import type InstancesWorker from '@/Workers/InstancesWorker'; import type HostsWorker from '@/Workers/HostsWorker'; import { type NotificationAnswer } from '@/Workers/HostsWorker'; diff --git a/packages/admin/src-admin/src/components/DrawerItem.tsx b/packages/admin/src-admin/src/components/DrawerItem.tsx index 13d0f6383..839cc8ec6 100644 --- a/packages/admin/src-admin/src/components/DrawerItem.tsx +++ b/packages/admin/src-admin/src/components/DrawerItem.tsx @@ -6,7 +6,7 @@ import { DragHandle } from '@mui/icons-material'; import { amber } from '@mui/material/colors'; import { Utils, ColorPicker, type IobTheme } from '@iobroker/adapter-react-v5'; -import AdminUtils from '../AdminUtils'; +import AdminUtils from '../helpers/AdminUtils'; const styles: Record = { selected: (theme: IobTheme) => ({ diff --git a/packages/admin/src-admin/src/components/Enums/EnumBlock.tsx b/packages/admin/src-admin/src/components/Enums/EnumBlock.tsx index 5881a0806..14aafb149 100644 --- a/packages/admin/src-admin/src/components/Enums/EnumBlock.tsx +++ b/packages/admin/src-admin/src/components/Enums/EnumBlock.tsx @@ -29,7 +29,7 @@ import { type Translate, } from '@iobroker/adapter-react-v5'; -import { isTouchDevice } from '@/helpers/utils'; +import AdminUtils from '@/helpers/AdminUtils'; import { type DragItem } from './DragObjectBrowser'; const boxShadowHover = '0 1px 1px 0 rgba(0, 0, 0, .4),0 6px 6px 0 rgba(0, 0, 0, .2)'; @@ -664,7 +664,7 @@ const EnumBlockDrag = (props: EnumBlockDragProps): JSX.Element => { ); } - return isTouchDevice() ? ( + return AdminUtils.isTouchDevice() ? (
= { mainGridCont: { @@ -877,7 +876,7 @@ class EnumsList extends Component { return ( <> - + = { ...genericStyles, diff --git a/packages/admin/src-admin/src/components/Instances/InstanceGeneric.tsx b/packages/admin/src-admin/src/components/Instances/InstanceGeneric.tsx index c3b156dc9..1d7a1e6cd 100644 --- a/packages/admin/src-admin/src/components/Instances/InstanceGeneric.tsx +++ b/packages/admin/src-admin/src/components/Instances/InstanceGeneric.tsx @@ -64,14 +64,13 @@ import { } from '@iobroker/adapter-react-v5'; import { amber, blue, green, grey, orange, red } from '@mui/material/colors'; -import { isTouchDevice } from '@/helpers/utils'; import State from '@/components/State'; import InstanceInfo from '@/components/Instances/InstanceInfo'; import sentry from '@/assets/sentry.svg'; import noSentry from '@/assets/sentryNo.svg'; import CustomModal from '../CustomModal'; import LinksDialog, { type InstanceLink } from './LinksDialog'; -import AdminUtils from '../../AdminUtils'; +import AdminUtils from '../../helpers/AdminUtils'; const arrayLogLevel = ['silly', 'debug', 'info', 'warn', 'error']; export const arrayTier = [ @@ -311,13 +310,13 @@ export const styles: Record = { }, editButton: { minHeight: 32, - '& .admin-edit-button': isTouchDevice() + '& .admin-edit-button': AdminUtils.isTouchDevice() ? undefined : { display: 'none', maxHeight: 32, }, - '&:hover': isTouchDevice() + '&:hover': AdminUtils.isTouchDevice() ? undefined : { '& .admin-edit-button': { diff --git a/packages/admin/src-admin/src/components/Instances/InstanceRow.tsx b/packages/admin/src-admin/src/components/Instances/InstanceRow.tsx index f1198eb15..358e93f93 100644 --- a/packages/admin/src-admin/src/components/Instances/InstanceRow.tsx +++ b/packages/admin/src-admin/src/components/Instances/InstanceRow.tsx @@ -4,7 +4,7 @@ import { Accordion, AccordionDetails, AccordionSummary, Avatar, Grid2, Tooltip, import { ExpandMore as ExpandMoreIcon } from '@mui/icons-material'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import InstanceInfo from './InstanceInfo'; import IsVisible from '../IsVisible'; import InstanceGeneric, { diff --git a/packages/admin/src-admin/src/components/Instances/LinksDialog.tsx b/packages/admin/src-admin/src/components/Instances/LinksDialog.tsx index 08a497148..0257b96dd 100644 --- a/packages/admin/src-admin/src/components/Instances/LinksDialog.tsx +++ b/packages/admin/src-admin/src/components/Instances/LinksDialog.tsx @@ -4,7 +4,7 @@ import { List, ListItemButton, ListItemText, DialogTitle, Dialog, ListItemAvatar import { I18n, type ThemeType, type Translate, Utils } from '@iobroker/adapter-react-v5'; -import AdminUtils from '../../AdminUtils'; +import AdminUtils from '../../helpers/AdminUtils'; const styles: Record = { img: { diff --git a/packages/admin/src-admin/src/components/Intro/IntroCard.tsx b/packages/admin/src-admin/src/components/Intro/IntroCard.tsx index eaf0cce90..6d5a53a69 100644 --- a/packages/admin/src-admin/src/components/Intro/IntroCard.tsx +++ b/packages/admin/src-admin/src/components/Intro/IntroCard.tsx @@ -28,7 +28,7 @@ import { blue, grey, red } from '@mui/material/colors'; import { Utils, IconCopy as SaveIcon, type IobTheme, type Translate } from '@iobroker/adapter-react-v5'; -import AdminUtils from '../../AdminUtils'; +import AdminUtils from '../../helpers/AdminUtils'; const boxShadow = '0 2px 2px 0 rgba(0, 0, 0, .14),0 3px 1px -2px rgba(0, 0, 0, .12),0 1px 5px 0 rgba(0, 0, 0, .2)'; const boxShadowHover = '0 8px 17px 0 rgba(0, 0, 0, .2),0 6px 20px 0 rgba(0, 0, 0, .19)'; diff --git a/packages/admin/src-admin/src/components/NotificationMessage.tsx b/packages/admin/src-admin/src/components/NotificationMessage.tsx index 17d4c8dd9..92cd721c4 100644 --- a/packages/admin/src-admin/src/components/NotificationMessage.tsx +++ b/packages/admin/src-admin/src/components/NotificationMessage.tsx @@ -146,7 +146,7 @@ class NotificationMessage extends Component { - if (this.props.message.contextData) { + if (this.props.message.contextData?.admin?.notification) { // request GUI for this notification const alive = await this.props.socket.getState(`${this.props.instanceId}.alive`); this.lastAlive = alive?.val ? Date.now() : 0; @@ -156,18 +156,20 @@ class NotificationMessage extends Component | null; schema: ConfigItemPanel | null }) => { if (result) { @@ -196,14 +198,15 @@ class NotificationMessage extends Component{Utils.renderTextWithA(text)}; } @@ -229,9 +232,7 @@ class NotificationMessage extends Component this.setState({ error })} - onChange={(_data: Record) => { - // ignore for now - }} + onChange={(data: Record) => this.setState({ data })} onBackEndCommand={(command?: BackEndCommandGeneric) => { if (command.schema) { this.setState({ schema: command.schema, data: command.data || this.state.data }); diff --git a/packages/admin/src-admin/src/components/Object/ObjectCustomEditor.tsx b/packages/admin/src-admin/src/components/Object/ObjectCustomEditor.tsx index a2709fde6..74ff6a294 100644 --- a/packages/admin/src-admin/src/components/Object/ObjectCustomEditor.tsx +++ b/packages/admin/src-admin/src/components/Object/ObjectCustomEditor.tsx @@ -18,7 +18,7 @@ import { ExpandMore as ExpandMoreIcon } from '@mui/icons-material'; import { withWidth, Error as DialogError, Confirm as ConfirmDialog, type IobTheme } from '@iobroker/adapter-react-v5'; import { ConfigGeneric, JsonConfigComponent, type ConfigItemPanel } from '@iobroker/json-config'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import type { BasicComponentProps } from '@/types'; const styles: Record = { diff --git a/packages/admin/src-admin/src/components/Users/UserEditDialog.tsx b/packages/admin/src-admin/src/components/Users/UserEditDialog.tsx index fbe84bcc0..f2e4cf100 100644 --- a/packages/admin/src-admin/src/components/Users/UserEditDialog.tsx +++ b/packages/admin/src-admin/src/components/Users/UserEditDialog.tsx @@ -17,7 +17,7 @@ import { import { Utils, IconPicker, type Translate } from '@iobroker/adapter-react-v5'; import { IOTextField, IOColorPicker } from '../IOFields/Fields'; -import AdminUtils from '../../AdminUtils'; +import AdminUtils from '../../helpers/AdminUtils'; import User1 from '../../assets/users/user1.svg'; import User2 from '../../assets/users/user2.svg'; diff --git a/packages/admin/src-admin/src/components/Users/UsersList.tsx b/packages/admin/src-admin/src/components/Users/UsersList.tsx index 0ae968637..a88d7eb13 100644 --- a/packages/admin/src-admin/src/components/Users/UsersList.tsx +++ b/packages/admin/src-admin/src/components/Users/UsersList.tsx @@ -11,7 +11,7 @@ import { PersonAdd as PersonAddIcon, GroupAdd as GroupAddIcon } from '@mui/icons import { Utils, type AdminConnection, type Translate, type IobTheme, type ThemeType } from '@iobroker/adapter-react-v5'; -import { isTouchDevice } from '@/helpers/utils'; +import AdminUtils from '@/helpers/AdminUtils'; import UserBlock from './UserBlock'; import GroupBlock from './GroupBlock'; import UserEditDialog from './UserEditDialog'; @@ -502,7 +502,7 @@ class UsersList extends Component { } return ( - + [] = [ diff --git a/packages/admin/src-admin/src/dialogs/NotificationsDialog.tsx b/packages/admin/src-admin/src/dialogs/NotificationsDialog.tsx index ae86e2bf5..465f75025 100644 --- a/packages/admin/src-admin/src/dialogs/NotificationsDialog.tsx +++ b/packages/admin/src-admin/src/dialogs/NotificationsDialog.tsx @@ -1,4 +1,4 @@ -import React, { useState, type JSX } from 'react'; +import React, { useState, type JSX, useEffect } from 'react'; import { Button, @@ -279,29 +279,11 @@ const NotificationsDialog = ({ isFloatComma, socket, }: NotificationDialogOptions): JSX.Element => { - const notificationManagerInstalled = !!Object.values(instances).find( - instance => instance.common.name === 'notification-manager', - ); - - const messages: MessagesPerScope = {}; - - for (const [host, hostDetails] of Object.entries(notifications)) { - for (const [scope, scopeDetails] of Object.entries(hostDetails.result)) { - if (scope === 'system') { - continue; - } - - for (const [category, categoryDetails] of Object.entries(scopeDetails.categories)) { - messages[scope] = messages[scope] || {}; - messages[scope][category] = { ...categoryDetails, host }; - } - } - } - const [panel, setPanel] = useState(''); const [disabled, setDisabled] = useState([]); const [expanded, setExpanded] = useState(''); const [autoCollapse, setAutoCollapse] = useState(true); + const [messages, setMessages] = useState({}); const handleChange = (_event: React.SyntheticEvent, newValue: string): void => { setAutoCollapse(true); @@ -314,28 +296,54 @@ const NotificationsDialog = ({ const black = themeType === 'dark'; - let firstKey = ''; - Object.keys(messages).map(scope => - Object.keys(messages[scope]).map(name => (firstKey = firstKey || `${scope}--${name}`)), + const notificationManagerInstalled = !!Object.values(instances).find( + instance => instance.common.name === 'notification-manager', ); - // if a panel does not exist, set it to the first one - if (panel) { - const [scope, name] = panel.split('--'); - if (!messages[scope]) { - setPanel(firstKey); - } else if (!messages[scope][name]) { - // find the first message in this scope - let found = false; - for (const key in messages[scope]) { - found = true; - setPanel(`${scope}--${key}`); - break; + + useEffect(() => { + const _messages: MessagesPerScope = {}; + let firstKey = ''; + + for (const [host, hostDetails] of Object.entries(notifications)) { + for (const [scope, scopeDetails] of Object.entries(hostDetails.result)) { + if (scope === 'system') { + continue; + } + + for (const [category, categoryDetails] of Object.entries(scopeDetails.categories)) { + _messages[scope] = _messages[scope] || {}; + _messages[scope][category] = { ...categoryDetails, host }; + } } - if (!found) { + } + + Object.keys(_messages).map(scope => + Object.keys(_messages[scope]).map(name => (firstKey = firstKey || `${scope}--${name}`)), + ); + + // if a panel does not exist, set it to the first one + if (panel) { + const [scope, name] = panel.split('--'); + if (!_messages[scope]) { setPanel(firstKey); + } else if (!_messages[scope][name]) { + // take the first message in this scope + const key = Object.keys(_messages[scope])[0]; + if (key) { + setPanel(`${scope}--${key}`); + } else { + setPanel(firstKey); + } } + } else { + setPanel(firstKey); } - } + setMessages(_messages); + }, [instances, notifications, panel]); + + const [currentScope, currentName] = panel.split('--'); + const entry: (Message & { host: string }) | null = + currentScope && currentName ? messages[currentScope][currentName] : null; return ( - {Object.keys(messages).map(scope => - Object.keys(messages[scope]).map(name => { - const key = `${scope}--${name}`; - if (panel === key || (!panel && key === firstKey)) { - const entry = messages[scope][name]; - console.log(`Active panel: ${panel}`, `Key: ${key}`); - return ( - - - {entry.name[I18n.getLanguage()]} - - - {entry.description[I18n.getLanguage()]} - -
- {entry.instances - ? Object.keys(entry.instances).map(nameInst => { - const accKey = `${key}--${nameInst}`; - if (autoCollapse) { - handleChangeAccordion(accKey)('', true); - setAutoCollapse(false); - } - - const currentInstance = instances && instances[nameInst]; - let icon = 'img/no-image.png'; - if ( - currentInstance?.common?.icon && - currentInstance?.common?.name - ) { - icon = `adapter/${currentInstance.common.name}/${currentInstance.common.icon}`; - } - - return ( - + + {entry.name[I18n.getLanguage()]} + + + {entry.description[I18n.getLanguage()]} + +
+ {entry.instances + ? Object.keys(entry.instances).map(nameInst => { + const accKey = `${panel}--${nameInst}`; + if (autoCollapse) { + handleChangeAccordion(accKey)('', true); + setAutoCollapse(false); + } + + const currentInstance = instances && instances[nameInst]; + let icon = 'img/no-image.png'; + if (currentInstance?.common?.icon && currentInstance?.common?.name) { + icon = `adapter/${currentInstance.common.name}/${currentInstance.common.icon}`; + } + + return ( + + } + sx={{ + '& .MuiAccordionSummary-content': styles.content, + }} + aria-controls="panel1bh-content" + id="panel1bh-header" + > + + + - } - sx={{ - '& .MuiAccordionSummary-content': styles.content, - }} - aria-controls="panel1bh-content" - id="panel1bh-header" - > - - - - {nameInst.replace(/^system\.adapter\./, '')} - - - - - {entry.instances[nameInst].messages.map((msg, i) => ( - onLink(linkCommand, nameInst, onClose)} - /> - ))} - - - ); - }) - : null} -
-
- - {Object.keys(messages[scope]).length === 1 && ( - - )} -
- - ); - } - return null; - }), - )} + {nameInst.replace(/^system\.adapter\./, '')} + + + + + {entry.instances[nameInst].messages.map((msg, i) => ( + + onLink(linkCommand, nameInst, onClose) + } + /> + ))} + +
+ ); + }) + : null} +
+
+ ) : null}
+ {currentScope && currentName ? ( + + ) : null} + {currentScope && currentName && Object.keys(messages[currentScope]).length === 1 && ( + + )} +
diff --git a/packages/admin/src-admin/src/dialogs/SystemSettingsDialog.tsx b/packages/admin/src-admin/src/dialogs/SystemSettingsDialog.tsx index 8e3b07300..6b9ad8b79 100644 --- a/packages/admin/src-admin/src/dialogs/SystemSettingsDialog.tsx +++ b/packages/admin/src-admin/src/dialogs/SystemSettingsDialog.tsx @@ -28,7 +28,7 @@ import { } from '@iobroker/adapter-react-v5'; import type { AdminGuiConfig } from '@/types'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import MainSettingsDialog from './SystemSettingsTabs/MainSettingsDialog'; import RepositoriesDialog from './SystemSettingsTabs/RepositoriesDialog'; import LicensesDialog from './SystemSettingsTabs/LicensesDialog'; diff --git a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/ACLDialog.tsx b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/ACLDialog.tsx index d4acd1921..02f99cbe9 100644 --- a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/ACLDialog.tsx +++ b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/ACLDialog.tsx @@ -19,7 +19,7 @@ import { import { I18n, withWidth, type Translate } from '@iobroker/adapter-react-v5'; import { type ioBrokerObject } from '@/types'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import BaseSystemSettingsDialog from './BaseSystemSettingsDialog'; const styles: Record = { diff --git a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/CertificatesDialog.tsx b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/CertificatesDialog.tsx index f11062d24..12e7403a5 100644 --- a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/CertificatesDialog.tsx +++ b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/CertificatesDialog.tsx @@ -20,7 +20,7 @@ import { Add as AddIcon, Delete as DeleteIcon, Close as CloseIcon } from '@mui/i import { withWidth, I18n, type Translate } from '@iobroker/adapter-react-v5'; import { type ioBrokerObject } from '@/types'; -import AdminUtils from '../../AdminUtils'; +import AdminUtils from '../../helpers/AdminUtils'; import BaseSystemSettingsDialog from './BaseSystemSettingsDialog'; // icons diff --git a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/MainSettingsDialog.tsx b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/MainSettingsDialog.tsx index 769b88924..a748966ea 100644 --- a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/MainSettingsDialog.tsx +++ b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/MainSettingsDialog.tsx @@ -25,7 +25,7 @@ import type { DragEndEvent, LatLngTuple, Map } from 'leaflet'; import { Confirm as ConfirmDialog, withWidth, I18n, type Translate } from '@iobroker/adapter-react-v5'; import { type AdminGuiConfig } from '@/types'; -import AdminUtils from '../../AdminUtils'; +import AdminUtils from '../../helpers/AdminUtils'; import countries from '../../assets/json/countries.json'; import BaseSystemSettingsDialog from './BaseSystemSettingsDialog'; diff --git a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/RepositoriesDialog.tsx b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/RepositoriesDialog.tsx index b6a665487..2cd6f711c 100644 --- a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/RepositoriesDialog.tsx +++ b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/RepositoriesDialog.tsx @@ -33,7 +33,7 @@ import { InfoBox } from '@foxriver76/iob-component-lib'; import type { AdminGuiConfig, ioBrokerObject } from '@/types'; import IsVisible from '@/components/IsVisible'; import { AUTO_UPGRADE_OPTIONS_MAPPING, AUTO_UPGRADE_SETTINGS } from '@/helpers/utils'; -import AdminUtils from '../../AdminUtils'; +import AdminUtils from '../../helpers/AdminUtils'; import BaseSystemSettingsDialog from './BaseSystemSettingsDialog'; const styles: Record = { diff --git a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/SSLDialog.tsx b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/SSLDialog.tsx index 5c41a4aba..91164de5b 100644 --- a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/SSLDialog.tsx +++ b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/SSLDialog.tsx @@ -6,7 +6,7 @@ import { Close as CloseIcon } from '@mui/icons-material'; import { withWidth, type Translate, type IobTheme } from '@iobroker/adapter-react-v5'; import type { ioBrokerObject } from '@/types'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import BaseSystemSettingsDialog from './BaseSystemSettingsDialog'; const styles: Record = { diff --git a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/StatisticsDialog.tsx b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/StatisticsDialog.tsx index 8719d3f4d..0c65bbda3 100644 --- a/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/StatisticsDialog.tsx +++ b/packages/admin/src-admin/src/dialogs/SystemSettingsTabs/StatisticsDialog.tsx @@ -15,7 +15,7 @@ import { import blueGrey from '@mui/material/colors/blueGrey'; import { withWidth, type Translate, type ThemeType } from '@iobroker/adapter-react-v5'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import Editor from '../../components/Editor'; import BaseSystemSettingsDialog from './BaseSystemSettingsDialog'; diff --git a/packages/admin/src-admin/src/helpers/AdminUtils.tsx b/packages/admin/src-admin/src/helpers/AdminUtils.tsx new file mode 100644 index 000000000..0ceedef2c --- /dev/null +++ b/packages/admin/src-admin/src/helpers/AdminUtils.tsx @@ -0,0 +1,435 @@ +import semver from 'semver'; +import { type Translate } from '@iobroker/adapter-react-v5'; + +declare module '@mui/material/Button' { + interface ButtonPropsColorOverrides { + grey: true; + } +} + +const ANSI_RESET = 0; +const ANSI_RESET_COLOR = 39; +const ANSI_RESET_BG_COLOR = 49; +const ANSI_BOLD = 1; +const ANSI_RESET_BOLD = 22; + +export interface Style { + color?: string; + backgroundColor?: string; + fontWeight?: string; +} + +const STYLES: Record = { + 30: { color: 'black' }, // ANSI_BLACK + 31: { color: 'red' }, // ANSI_RED + 32: { color: 'green' }, // ANSI_GREEN + 33: { color: 'yellow' }, // ANSI_YELLOW + 34: { color: 'blue' }, // ANSI_BLUE + 35: { color: 'purple' }, // ANSI_PURPLE + 36: { color: 'cyan' }, // ANSI_CYAN + 37: { color: 'white' }, // ANSI_WHITE + + 90: { color: 'grey' }, // ANSI_BRIGHT_BLACK + 91: { color: 'lightred' }, // ANSI_BRIGHT_RED + 92: { color: 'lightgreen' }, // ANSI_BRIGHT_GREEN + 93: { color: 'lightyellow' }, // ANSI_BRIGHT_YELLOW + 94: { color: 'lightblue' }, // ANSI_BRIGHT_BLUE + 95: { color: 'lightpurple' }, // ANSI_BRIGHT_PURPLE + 96: { color: 'lightcyan' }, // ANSI_BRIGHT_CYAN + 97: { color: 'white' }, // ANSI_BRIGHT_WHITE + + 40: { backgroundColor: 'black' }, // ANSI_BG_BLACK + 41: { backgroundColor: 'red' }, // ANSI_BG_RED + 42: { backgroundColor: 'green' }, // ANSI_BG_GREEN + 43: { backgroundColor: 'yellow' }, // ANSI_BG_YELLOW + 44: { backgroundColor: 'blue' }, // ANSI_BG_BLUE + 45: { backgroundColor: 'purple' }, // ANSI_BG_PURPLE + 46: { backgroundColor: 'cyan' }, // ANSI_BG_CYAN + 47: { backgroundColor: 'white' }, // ANSI_BG_WHITE + + 100: { backgroundColor: 'grey' }, // ANSI_BRIGHT_BG_BLACK + 101: { backgroundColor: 'lightred' }, // ANSI_BRIGHT_BG_RED + 102: { backgroundColor: 'lightgreen' }, // ANSI_BRIGHT_BG_GREEN + 103: { backgroundColor: 'lightyellow' }, // ANSI_BRIGHT_BG_YELLOW + 104: { backgroundColor: 'lightblue' }, // ANSI_BRIGHT_BG_BLUE + 105: { backgroundColor: 'lightpurple' }, // ANSI_BRIGHT_BG_PURPLE + 106: { backgroundColor: 'lightcyan' }, // ANSI_BRIGHT_BG_CYAN + 107: { backgroundColor: 'white' }, // ANSI_BRIGHT_BG_WHITE +}; + +class AdminUtils { + /** + * Perform JSON parse/stringify with type inference + * + * @param obj the object to clone + */ + static deepClone>(obj: T): T { + return JSON.parse(JSON.stringify(obj)); + } + + /** + * Format bytes to MB or GB + * + * @param bytes the number of bytes + */ + static formatRam(bytes: number): string { + const GB = Math.floor((bytes / (1024 * 1024 * 1024)) * 10) / 10; + bytes %= 1024 * 1024 * 1024; + const MB = Math.floor((bytes / (1024 * 1024)) * 10) / 10; + let text = ''; + + if (GB > 1) { + text += `${GB} GB`; + } else { + text += `${MB} MB`; + } + + return text; + } + + static isTouchDevice(): boolean { + return 'ontouchstart' in window || window.navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0; + } + + static formatSpeed(mhz: number): string { + return `${mhz} MHz`; + } + + static formatBytes(bytes: number): string { + if (Math.abs(bytes) < 1024) { + return `${bytes} B`; + } + + const units = ['KB', 'MB', 'GB']; + // const units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']; + let u = -1; + + do { + bytes /= 1024; + ++u; + } while (Math.abs(bytes) >= 1024 && u < units.length - 1); + + return `${bytes.toFixed(1)} ${units[u]}`; + } + + static getFileExtension(fileName: string): string | null { + const pos = fileName.lastIndexOf('.'); + if (pos !== -1) { + return fileName.substring(pos + 1).toLowerCase(); + } + return null; + } + + // Big thanks to: https://stackoverflow.com/questions/35969656/how-can-i-generate-the-opposite-color-according-to-current-color + static invertColor(hex: string, bw: boolean): string { + if (hex === undefined || hex === null || hex === '' || typeof hex !== 'string') { + return ''; + } + if (hex.indexOf('#') === 0) { + hex = hex.slice(1); + } + // convert 3-digit hex to 6-digits. + if (hex.length === 3) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + if (hex.length !== 6) { + throw new Error('Invalid HEX color.'); + } + const r = parseInt(hex.slice(0, 2), 16); + const g = parseInt(hex.slice(2, 4), 16); + const b = parseInt(hex.slice(4, 6), 16); + + if (bw) { + // http://stackoverflow.com/a/3943023/112731 + return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? '#000000' : '#FFFFFF'; + } + // invert color components + const finalR = (255 - r).toString(16); + const finalG = (255 - g).toString(16); + const finalB = (255 - b).toString(16); + // pad each with zeros and return + return `#${finalR.padStart(2, '0')}${finalG.padStart(2, '0')}${finalB.padStart(2, '0')}`; + } + + /** + * Format number in seconds to time text + * + * @param seconds the number of seconds + * @param t i18n.t function + */ + static formatSeconds(seconds: number, t: Translate): string { + const days = Math.floor(seconds / (3600 * 24)); + let minutesRes: string; + let secondsRes: string; + let hoursRes: string; + + seconds %= 3600 * 24; + const hours = Math.floor(seconds / 3600); + + if (hours < 10) { + hoursRes = `0${hours}`; + } else { + hoursRes = hours.toString(); + } + seconds %= 3600; + const minutes = Math.floor(seconds / 60); + if (minutes < 10) { + minutesRes = `0${minutes}`; + } else { + minutesRes = minutes.toString(); + } + + seconds %= 60; + seconds = Math.floor(seconds); + if (seconds < 10) { + secondsRes = `0${seconds}`; + } else { + secondsRes = seconds.toString(); + } + + let text = ''; + if (days) { + text += `${days} ${t('daysShortText')} `; + } + text += `${hoursRes}:${minutesRes}:${secondsRes}`; + + return text; + } + + static objectMap( + object: Record, + callback: (res: Value, key: string) => Result, + ): Result[] { + const result: Result[] = []; + for (const key in object) { + result.push(callback(object[key], key)); + } + return result; + } + + static fixAdminUI(obj: Record): void { + if (obj?.common) { + if (!obj.common.adminUI) { + if (obj.common.noConfig) { + obj.common.adminUI = obj.common.adminUI || {}; + obj.common.adminUI.config = 'none'; + } else if (obj.common.jsonConfig) { + obj.common.adminUI = obj.common.adminUI || {}; + obj.common.adminUI.config = 'json'; + } else if (obj.common.materialize) { + obj.common.adminUI = obj.common.adminUI || {}; + obj.common.adminUI.config = 'materialize'; + } else { + obj.common.adminUI = obj.common.adminUI || {}; + obj.common.adminUI.config = 'html'; + } + + if (obj.common.jsonCustom) { + obj.common.adminUI = obj.common.adminUI || {}; + obj.common.adminUI.custom = 'json'; + } else if (obj.common.supportCustoms) { + obj.common.adminUI = obj.common.adminUI || {}; + obj.common.adminUI.custom = 'json'; + } + + if (obj.common.materializeTab && obj.common.adminTab) { + obj.common.adminUI = obj.common.adminUI || {}; + obj.common.adminUI.tab = 'materialize'; + } else if (obj.common.adminTab) { + obj.common.adminUI = obj.common.adminUI || {}; + obj.common.adminUI.tab = 'html'; + } + + if (obj.common.adminUI) { + console.warn( + `Please add to "${obj._id.replace(/\.\d+$/, '')}" common.adminUI=${JSON.stringify(obj.common.adminUI)}`, + ); + } + } else { + let changed = false; + if (obj.common.materializeTab && obj.common.adminTab) { + if (obj.common.adminUI.tab !== 'materialize') { + obj.common.adminUI.tab = 'materialize'; + changed = true; + } + } else if (obj.common.adminTab) { + if (obj.common.adminUI.tab !== 'html' && obj.common.adminUI.tab !== 'materialize') { + obj.common.adminUI.tab = 'html'; + changed = true; + } + } + + if (obj.common.jsonCustom || obj.common.supportCustoms) { + if (obj.common.adminUI.custom !== 'json') { + obj.common.adminUI.custom = 'json'; + changed = true; + } + } + + if (obj.common.noConfig) { + if (obj.common.adminUI.config !== 'none') { + obj.common.adminUI.config = 'none'; + changed = true; + } + } else if (obj.common.jsonConfig) { + if (obj.common.adminUI.config !== 'json') { + obj.common.adminUI.config = 'json'; + changed = true; + } + obj.common.adminUI.config = 'json'; + } else if (obj.common.materialize) { + if (obj.common.adminUI.config !== 'materialize') { + if (!obj.common.adminUI.config) { + obj.common.adminUI.config = 'materialize'; + changed = true; + } + } + } else if (!obj.common.adminUI.config) { + obj.common.adminUI.config = 'html'; + changed = true; + } + if (changed) { + console.warn( + `Please modify "${obj._id.replace(/\.\d+$/, '')}" common.adminUI=${JSON.stringify(obj.common.adminUI)}`, + ); + } + } + } + } + + static parseColorMessage(text: string): string | { original: string; parts: { text: string; style: Style }[] } { + if (text && (text.includes('\u001b[') || text.includes('\u001B['))) { + // eslint-disable-next-line + let m = text.match(/\u001b\[\d+m/gi); + if (m) { + const original = text; + const result = []; + let style: Style = {}; + for (let i = 0; i < m.length; i++) { + const pos = text.indexOf(m[i]); + if (pos) { + result.push({ text: text.substring(0, pos), style: { ...style } }); + } + const code = parseInt(m[i].substring(2), 10); + if (STYLES[code]) { + Object.assign(style, STYLES[code]); + } else if (ANSI_RESET_COLOR === code) { + delete style.color; + } else if (ANSI_RESET_BG_COLOR === code) { + delete style.backgroundColor; + } else if (ANSI_RESET_BOLD === code) { + delete style.fontWeight; + } else if (ANSI_BOLD === code) { + style.fontWeight = 'bold'; + } else if (ANSI_RESET === code) { + style = {}; + } + text = text.substring(m[i].length + pos); + } + if (text) { + result.push({ text, style: { ...style } }); + } + + return { original, parts: result }; + } + return text; + } + return text; + } + + static PASSWORD_ERROR_LENGTH = + 'Password must be at least 8 characters long and have numbers, upper and lower case letters'; + + static PASSWORD_ERROR_NOT_EQUAL = 'Repeat password is not equal with password'; + + static PASSWORD_ERROR_EMPTY = 'Empty password is not allowed'; + + static PASSWORD_SET = '***********'; + + /** The languages for which docs are generated */ + static SUPPORTED_DOC_LANGUAGES: ioBroker.Languages[] = ['en', 'de', 'ru', 'zh-cn']; + + static checkPassword(password: string, passwordRepeat?: string): false | string { + password = password || ''; + passwordRepeat = passwordRepeat || ''; + if ( + password && + passwordRepeat && + password !== AdminUtils.PASSWORD_SET && + passwordRepeat !== AdminUtils.PASSWORD_SET + ) { + if (password.length < 8 || !password.match(/\d/) || !password.match(/[a-z]/) || !password.match(/[A-Z]/)) { + return AdminUtils.PASSWORD_ERROR_LENGTH; + } + if (password !== passwordRepeat) { + return AdminUtils.PASSWORD_ERROR_NOT_EQUAL; + } + return false; + } + if (password && password !== AdminUtils.PASSWORD_SET) { + if (password.length < 8 || !password.match(/\d/) || !password.match(/[a-z]/) || !password.match(/[A-Z]/)) { + return AdminUtils.PASSWORD_ERROR_LENGTH; + } + return false; + } + if (passwordRepeat && passwordRepeat !== AdminUtils.PASSWORD_SET) { + if ( + passwordRepeat.length < 8 || + !passwordRepeat.match(/\d/) || + !passwordRepeat.match(/[a-z]/) || + !passwordRepeat.match(/[A-Z]/) + ) { + return AdminUtils.PASSWORD_ERROR_LENGTH; + } + return false; + } + if (password === AdminUtils.PASSWORD_SET || passwordRepeat === AdminUtils.PASSWORD_SET) { + return false; + } + return AdminUtils.PASSWORD_ERROR_EMPTY; + } + + /** + * Get Link to adapter docs in given language + * + * @param options the adapter name without ioBroker. prefix and the language information + * @param options.adapterName the adapter name without ioBroker. prefix + * @param options.lang the language for the docs + */ + static getDocsLinkForAdapter(options: { lang: ioBroker.Languages; adapterName: string }): string { + const { adapterName } = options; + let { lang } = options; + + if (!AdminUtils.SUPPORTED_DOC_LANGUAGES.includes(lang)) { + lang = 'en'; + } + + return `https://www.iobroker.net/#${lang}/adapters/adapterref/iobroker.${adapterName}/README.md`; + } + + static updateAvailable(oldVersion: string, newVersion: string): boolean { + try { + return semver.gt(newVersion, oldVersion) === true; + } catch { + console.warn(`[ADAPTERS] Cannot compare "${newVersion}" and "${oldVersion}"`); + return false; + } + } + + static getText(word: ioBroker.StringOrTranslated, lang: ioBroker.Languages): string { + if (typeof word === 'object') { + if (!word) { + return ''; + } + return (word[lang] || word.en || '').toString(); + } + + return word ? word.toString() : ''; + } + + static clone(obj: T): T { + return JSON.parse(JSON.stringify(obj)); + } +} + +export default AdminUtils; diff --git a/packages/admin/src-admin/src/helpers/utils.ts b/packages/admin/src-admin/src/helpers/utils.ts index 20347c13a..6504ee8b6 100644 --- a/packages/admin/src-admin/src/helpers/utils.ts +++ b/packages/admin/src-admin/src/helpers/utils.ts @@ -1,22 +1,3 @@ -/** - * Tests whether the given variable is a real object and not an Array - * - * @param it The variable to test - * @returns true if it is Record - */ -export function isObject(it: any): it is Record { - // This is necessary because: - // typeof null === 'object' - // typeof [] === 'object' - // [] instanceof Object === true - return Object.prototype.toString.call(it) === '[object Object]'; // this code is 25% faster than below one - // return it && typeof it === 'object' && !(it instanceof Array); -} - -export function isTouchDevice(): boolean { - return 'ontouchstart' in window || window.navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0; -} - /** Url where controller changelog is reachable */ export const CONTROLLER_CHANGELOG_URL = 'https://github.com/ioBroker/ioBroker.js-controller/blob/master/CHANGELOG.md'; @@ -30,3 +11,431 @@ export const AUTO_UPGRADE_OPTIONS_MAPPING: Record (ipInt << 8) + parseInt(octet, 10), 0) >>> 0; +} + +function findNetworkAddressOfHost(obj: ioBroker.HostObject, localIp: string): null | string { + const networkInterfaces = obj?.native?.hardware?.networkInterfaces; + if (!networkInterfaces) { + return null; + } + + let hostIp; + for (const networkInterface of Object.values(networkInterfaces)) { + if (!networkInterface) { + continue; + } + for (let i = 0; i < networkInterface.length; i++) { + const ip = networkInterface[i]; + if (ip.internal) { + return; + } + if (localIp.includes(':') && ip.family !== 'IPv6') { + return; + } + if (localIp.includes('.') && !localIp.match(/[^.\d]/) && ip.family !== 'IPv4') { + return; + } + if (localIp === '127.0.0.0' || localIp === 'localhost' || localIp.match(/[^.\d]/)) { + // if DNS name + hostIp = ip.address; + } else if ( + ip.family === 'IPv4' && + localIp.includes('.') && + (ip2int(localIp) & ip2int(ip.netmask)) === (ip2int(ip.address) & ip2int(ip.netmask)) + ) { + hostIp = ip.address; + } else { + hostIp = ip.address; + } + } + } + + if (!hostIp) { + for (const networkInterface of Object.values(networkInterfaces)) { + if (!networkInterface) { + continue; + } + for (let i = 0; i < networkInterface.length; i++) { + const ip = networkInterface[i]; + if (ip.internal) { + return; + } + if (localIp.includes(':') && ip.family !== 'IPv6') { + return; + } + if (localIp.includes('.') && !localIp.match(/[^.\d]/) && ip.family !== 'IPv4') { + return; + } + if (localIp === '127.0.0.0' || localIp === 'localhost' || localIp.match(/[^.\d]/)) { + // if DNS name + hostIp = ip.address; + } else { + hostIp = ip.address; + } + } + } + } + + if (!hostIp) { + for (const networkInterface of Object.values(networkInterfaces)) { + if (!networkInterface) { + continue; + } + for (let i = 0; i < networkInterface.length; i++) { + const ip = networkInterface[i]; + if (ip.internal) { + return; + } + hostIp = ip.address; + } + } + } + + return hostIp; +} + +function getHostname( + instanceObj: ioBroker.InstanceObject, + objects: Record, + hosts: Record, + currentHostname: string, + adminInstance: string, +): string { + if (!instanceObj || !instanceObj.common) { + return null; + } + + let hostname; + // check if the adapter from the same host as admin + const adminHost = objects[`system.adapter.${adminInstance}`]?.common?.host; + if (instanceObj.common.host !== adminHost) { + // find IP address + const host = hosts[`system.host.${instanceObj.common.host}`]; + if (host) { + const ip = findNetworkAddressOfHost(host, currentHostname); + if (ip) { + hostname = ip; + } else { + console.warn(`Cannot find suitable IP in host ${instanceObj.common.host} for ${instanceObj._id}`); + return null; + } + } else { + console.warn(`Cannot find host ${instanceObj.common.host} for ${instanceObj._id}`); + return null; + } + } else { + hostname = currentHostname; + } + + return hostname; +} + +// internal use +function _replaceLink( + link: string, + objects: Record, + adapterInstance: string, + attr: string, + placeholder: string, + hosts: Record, + hostname: string, + adminInstance: string, +): string { + if (attr === 'protocol') { + attr = 'secure'; + } + + try { + const object = objects[`system.adapter.${adapterInstance}`]; + + if (link && object) { + if (attr === 'secure') { + link = link.replace(`%${placeholder}%`, object.native[attr] ? 'https' : 'http'); + } else { + let value = object.native[attr]; + // workaround for port + if ((attr === 'webinterfacePort' || attr === 'port') && (!value || value === '0')) { + if (object.native.secure === true) { + value = 443; + } else { + value = 80; + } + } + + if (attr === 'bind' || attr === 'ip') { + let ip = object.native.bind || object.native.ip; + if (ip === '0.0.0.0') { + ip = getHostname(object, objects, hosts, hostname, adminInstance); + } + if (!link.includes(`%${placeholder}%`)) { + link = link.replace(`%native_${placeholder}%`, ip || ''); + } else { + link = link.replace(`%${placeholder}%`, ip || ''); + } + } else if (!link.includes(`%${placeholder}%`)) { + link = link.replace(`%native_${placeholder}%`, value); + } else { + link = link.replace(`%${placeholder}%`, value); + } + } + } else { + console.log(`Cannot get link ${attr}`); + link = link.replace(`%${placeholder}%`, ''); + } + } catch (error) { + console.log(error); + } + return link; +} + +/** + * Convert the template link to string + * + * Possible placeholders: + * `%ip%` - `native.bind` or `native.ip` of this adapter. If it is '0.0.0.0', we are trying to find the host IP that is reachable from the current browser. + * `%protocol%` - `native.protocol` or `native.secure` of this adapter. The result is 'http' or 'https'. + * `%s%` - `native.protocol` or `native.secure` of this adapter. The result is '' or 's'. The idea is to use the pattern like "http%s%://..." + * `%instance%` - instance number + * `%adapterName_nativeAttr%` - Takes the native value `nativeAttr` of all instances of adapterName. This generates many links if more than one instance installed + * `%adapterName.x_nativeAttr%` - Takes the native value `nativeAttr` of adapterName.x instance + * + * @param link pattern for link + * @param adapter adapter name + * @param instance adapter instance number + * @param context Context object + * @param context.instances Object with all instances + * @param context.hostname Actual host name + * @param context.adminInstance Actual admin instance + * @param context.hosts Object with all hosts + */ +export function replaceLink( + link: string, + adapter: string, + instance: number, + context: { + instances: Record; + hostname: string; + adminInstance: string; + hosts: Record; + }, +): { + url: string; + port: number; + instance?: string; +}[] { + const _urls: { + url: string; + port: number; + instance?: string; + }[] = []; + let port: number; + + if (link) { + const instanceObj = context.instances[`system.adapter.${adapter}.${instance}`]; + const native = instanceObj?.native || {}; + + const placeholders = link.match(/%(\w+)%/g); + + if (placeholders) { + for (let p = 0; p < placeholders.length; p++) { + let placeholder = placeholders[p]; + + if (placeholder === '%ip%') { + let ip: string = (native.bind || native.ip) as string; + if (!ip || ip === '0.0.0.0') { + // Check host + ip = getHostname( + instanceObj, + context.instances, + context.hosts, + context.hostname, + context.adminInstance, + ); + } + + if (_urls.length) { + _urls.forEach(item => (item.url = item.url.replace('%ip%', ip))); + } else { + link = link.replace('%ip%', ip || ''); + } + } else if (placeholder === '%protocol%') { + const protocolVal: string | boolean = native.secure === undefined ? native.protocol : native.secure; + let protocol: 'http' | 'https'; + if (protocolVal === true || protocolVal === 'true') { + protocol = 'https'; + } else if (protocolVal === false || protocolVal === 'false' || !protocolVal) { + protocol = 'http'; + } else { + protocol = protocolVal.toString().replace(/:$/, '') as 'http' | 'https'; + } + + if (_urls.length) { + _urls.forEach(item => (item.url = item.url.replace('%protocol%', protocol))); + } else { + link = link.replace('%protocol%', protocol); + } + } else if (placeholder === '%s%') { + const protocolVal: string | boolean = native.secure === undefined ? native.protocol : native.secure; + let protocol: '' | 's'; + if (protocolVal === true || protocolVal === 'true') { + protocol = 's'; + } else if (protocolVal === false || protocolVal === 'false' || !protocolVal) { + protocol = ''; + } else { + protocol = protocolVal.toString().replace(/:$/, '') as '' | 's'; + } + + if (_urls.length) { + _urls.forEach(item => (item.url = item.url.replace('%s%', protocol))); + } else { + link = link.replace('%s%', protocol); + } + } else if (placeholder === '%instance%') { + link = link.replace('%instance%', instance.toString()); + if (_urls.length) { + _urls.forEach(item => (item.url = item.url.replace('%instance%', instance.toString()))); + } else { + link = link.replace('%instance%', instance.toString()); + } + } else { + // remove %% + placeholder = placeholder.replace(/%/g, ''); + + if (placeholder.startsWith('native_')) { + placeholder = placeholder.substring(7); + } + + // like web.0_port or web_protocol + if (!placeholder.includes('_')) { + // if only one instance + const adapterInstance = `${adapter}.${instance}`; + if (_urls.length) { + _urls.forEach( + item => + (item.url = _replaceLink( + item.url, + context.instances, + adapterInstance, + placeholder, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + )), + ); + } else { + link = _replaceLink( + link, + context.instances, + adapterInstance, + placeholder, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + port = context.instances[`system.adapter.${adapterInstance}`]?.native?.port; + } + } else { + const [adapterInstance, attr] = placeholder.split('_'); + + // if instance number not found + if (!adapterInstance.match(/\.[0-9]+$/)) { + // list all possible instances + let ids: string[]; + if (adapter === adapterInstance) { + // take only this one instance and that's all + ids = [`${adapter}.${instance}`]; + } else { + ids = Object.keys(context.instances) + .filter( + id => + id.startsWith(`system.adapter.${adapterInstance}.`) && + context.instances[id].common.enabled, + ) + .map(id => id.substring(15)); + + // try to get disabled instances + if (!ids.length) { + ids = Object.keys(context.instances) + .filter(id => id.startsWith(`system.adapter.${adapterInstance}.`)) + .map(id => id.substring(15)); + } + } + + for (const id of ids) { + if (_urls.length) { + const item = _urls.find(t => t.instance === id); + if (item) { + item.url = _replaceLink( + item.url, + context.instances, + id, + attr, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + } else { + // add new + const _link = _replaceLink( + link, + context.instances, + id, + attr, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + const _port: number = context.instances[`system.adapter.${id}`]?.native + ?.port as number; + + _urls.push({ url: _link, port: _port, instance: id }); + } + } else { + const _link = _replaceLink( + link, + context.instances, + id, + attr, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + + const _port: number = context.instances[`system.adapter.${id}`]?.native + ?.port as number; + _urls.push({ url: _link, port: _port, instance: id }); + } + } + } else { + link = _replaceLink( + link, + context.instances, + adapterInstance, + attr, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + + port = context.instances[`system.adapter.${adapterInstance}`]?.native?.port as number; + } + } + } + } + } + } + + if (_urls.length) { + return _urls; + } + return [{ url: link, port }]; +} diff --git a/packages/admin/src-admin/src/tabs/Adapters.tsx b/packages/admin/src-admin/src/tabs/Adapters.tsx index 3bccafaf7..4ee398a60 100644 --- a/packages/admin/src-admin/src/tabs/Adapters.tsx +++ b/packages/admin/src-admin/src/tabs/Adapters.tsx @@ -33,7 +33,7 @@ import CustomSelectButton from '@/components/CustomSelectButton'; import AdaptersUpdaterDialog from '@/dialogs/AdaptersUpdaterDialog'; import SlowConnectionWarningDialog, { SlowConnectionWarningDialogClass } from '@/dialogs/SlowConnectionWarningDialog'; import IsVisible from '@/components/IsVisible'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; import { TabHeader, type AdminConnection, diff --git a/packages/admin/src-admin/src/tabs/Config.tsx b/packages/admin/src-admin/src/tabs/Config.tsx index 8c5e4dadf..b13b54223 100644 --- a/packages/admin/src-admin/src/tabs/Config.tsx +++ b/packages/admin/src-admin/src/tabs/Config.tsx @@ -46,7 +46,7 @@ import { import { type DeviceManagerPropsProps, JsonConfig } from '@iobroker/json-config'; import DeviceManager from '@iobroker/dm-gui-components'; -import AdminUtils from '../AdminUtils'; +import AdminUtils from '../helpers/AdminUtils'; const arrayLogLevel: ioBroker.LogLevel[] = ['silly', 'debug', 'info', 'warn', 'error']; diff --git a/packages/admin/src-admin/src/tabs/CustomTab.tsx b/packages/admin/src-admin/src/tabs/CustomTab.tsx index 2672f725b..91b2d403f 100644 --- a/packages/admin/src-admin/src/tabs/CustomTab.tsx +++ b/packages/admin/src-admin/src/tabs/CustomTab.tsx @@ -4,7 +4,8 @@ import { LinearProgress } from '@mui/material'; import { withWidth, type ThemeType, Router } from '@iobroker/adapter-react-v5'; import type InstancesWorker from '@/Workers/InstancesWorker'; -import AdminUtils from '../AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; +import { replaceLink } from '@/helpers/utils'; const styles: Record = { root: { @@ -77,7 +78,7 @@ export async function getHref( } // replace - const hrefs = AdminUtils.replaceLink(href, adapter, _instNum, { + const hrefs = replaceLink(href, adapter, _instNum, { hostname, // it cannot be void instances: instances as Record, diff --git a/packages/admin/src-admin/src/tabs/Instances.tsx b/packages/admin/src-admin/src/tabs/Instances.tsx index de1e387ff..b8ae3cf58 100644 --- a/packages/admin/src-admin/src/tabs/Instances.tsx +++ b/packages/admin/src-admin/src/tabs/Instances.tsx @@ -33,7 +33,8 @@ import { type Translate, } from '@iobroker/adapter-react-v5'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; +import { replaceLink } from '@/helpers/utils'; import type InstancesWorker from '@/Workers/InstancesWorker'; import type { InstanceLink } from '@/components/Instances/LinksDialog'; import Config from './Config'; @@ -419,7 +420,7 @@ class Instances extends Component { } const urls = - AdminUtils.replaceLink(link.link, common.name, instanceId, { + replaceLink(link.link, common.name, instanceId, { instances: instancesFromWorker, hostname: this.props.hostname, hosts, diff --git a/packages/admin/src-admin/src/tabs/Intro.tsx b/packages/admin/src-admin/src/tabs/Intro.tsx index 2a37142de..bf6d2b344 100644 --- a/packages/admin/src-admin/src/tabs/Intro.tsx +++ b/packages/admin/src-admin/src/tabs/Intro.tsx @@ -24,7 +24,8 @@ import { import type InstancesWorker from '@/Workers/InstancesWorker'; import type HostsWorker from '@/Workers/HostsWorker'; import { type HostAliveEvent, type HostEvent } from '@/Workers/HostsWorker'; -import AdminUtils from '@/AdminUtils'; +import AdminUtils from '@/helpers/AdminUtils'; +import { replaceLink } from '@/helpers/utils'; import IntroCard from '@/components/Intro/IntroCard'; import EditIntroLinkDialog from '@/components/Intro/EditIntroLinkDialog'; @@ -32,6 +33,20 @@ import { type InstanceEvent } from '@/Workers/InstancesWorker'; import NodeUpdateDialog from '@/dialogs/NodeUpdateDialog'; import IntroCardCamera from '@/components/Intro/IntroCardCamera'; +type OldLinkStructure = { + link: string; + color?: string; + order?: number | string; + icon?: string; + img?: string; + description?: ioBroker.StringOrTranslated; + pro?: string | boolean; + cloud?: string; + intro?: boolean; + name?: ioBroker.StringOrTranslated; + localLinks?: string; +}; + export type CompactHost = { _id: `system.host.${string}`; common: { @@ -834,7 +849,7 @@ class Intro extends React.Component { url: string; port: number; instance?: string; - }[] = AdminUtils.replaceLink(linkItem.link, common.name, instanceId, { + }[] = replaceLink(linkItem.link, common.name, instanceId, { instances, hostname: this.props.hostname, adminInstance: this.props.adminInstance, @@ -900,7 +915,8 @@ class Intro extends React.Component { id: instance._id.replace('system.adapter.', ''), link: '', name: Intro.getText(instance.common.titleLang || instance.common.title || instance.common.name, language), - order: 1000, + // @ts-expect-error order in common is deprecated, but could happen + order: instance.common.order || 1000, intro: true, description: Intro.getText(instance.common.desc, language), icon: instance.common.icon ? `adapter/${instance.common.name}/${instance.common.icon}` : 'img/no-image.png', @@ -913,10 +929,16 @@ class Intro extends React.Component { link: instance.common.localLink, }); } else { - const compatibilityStructure: Record = instance.common.localLink as unknown as Record< - string, - any - >; + // localLink is an object + /* + { + link: string; + color: string; + order: number; + icon: string; + } + */ + const compatibilityStructure: OldLinkStructure = instance.common.localLink as OldLinkStructure; if (compatibilityStructure.link) { const item: LinkItem = { ...defaultLink, @@ -951,7 +973,7 @@ class Intro extends React.Component { link: linkItem, }); } else { - const compatibilityStructure: Record = linkItem as Record; + const compatibilityStructure: OldLinkStructure = linkItem as OldLinkStructure; if (compatibilityStructure.link) { const item: LinkItem = { @@ -963,19 +985,16 @@ class Intro extends React.Component { name: defaultLink.name + (linkName === '_default' ? '' : ` ${linkName}`), }; if (compatibilityStructure.color) { - item.color = compatibilityStructure.color as string; + item.color = compatibilityStructure.color; } if (compatibilityStructure.order !== undefined) { item.order = parseInt(compatibilityStructure.order as string, 10) || 1000; } if (compatibilityStructure.icon && compatibilityStructure.img) { - item.icon = (compatibilityStructure.icon || compatibilityStructure.img) as string; + item.icon = compatibilityStructure.icon || compatibilityStructure.img; } if (compatibilityStructure.description) { - item.description = Intro.getText( - compatibilityStructure.description as ioBroker.StringOrTranslated, - language, - ); + item.description = Intro.getText(compatibilityStructure.description, language); } if (compatibilityStructure.pro !== undefined) { if (typeof compatibilityStructure.pro === 'string') { @@ -985,17 +1004,14 @@ class Intro extends React.Component { } } if (compatibilityStructure.cloud !== undefined) { - item.cloud = compatibilityStructure.cloud as string; + item.cloud = compatibilityStructure.cloud; } if (compatibilityStructure.intro !== undefined) { item.intro = compatibilityStructure.intro === true; } if (compatibilityStructure.name) { - item.name = Intro.getText( - compatibilityStructure.name as ioBroker.StringOrTranslated, - language, - ); + item.name = Intro.getText(compatibilityStructure.name, language); } if (linkName === '_default') { item.default = true; @@ -1010,9 +1026,10 @@ class Intro extends React.Component { } if (instance.common.welcomeScreen && typeof instance.common.welcomeScreen === 'object') { - const compatibilityStructureArr: Record[] = Array.isArray(instance.common.welcomeScreen) - ? (instance.common.welcomeScreen as Record[]) - : [instance.common.welcomeScreen as Record]; + const compatibilityStructureArr: OldLinkStructure[] = Array.isArray(instance.common.welcomeScreen) + ? (instance.common.welcomeScreen as OldLinkStructure[]) + : [instance.common.welcomeScreen as OldLinkStructure]; + compatibilityStructureArr.forEach(compatibilityStructure => { if (compatibilityStructure.link) { const item: LinkItem = { @@ -1044,7 +1061,7 @@ class Intro extends React.Component { } if (compatibilityStructure.name) { - item.name = Intro.getText(compatibilityStructure.name as ioBroker.StringOrTranslated, language); + item.name = Intro.getText(compatibilityStructure.name, language); } result.push(item); @@ -1052,11 +1069,9 @@ class Intro extends React.Component { }); if (instance.common.welcomeScreenPro && typeof instance.common.welcomeScreenPro === 'object') { - const _compatibilityStructureArr: Record[] = Array.isArray( - instance.common.welcomeScreenPro, - ) - ? (instance.common.welcomeScreenPro as Record[]) - : [instance.common.welcomeScreenPro as Record]; + const _compatibilityStructureArr: OldLinkStructure[] = Array.isArray(instance.common.welcomeScreenPro) + ? (instance.common.welcomeScreenPro as OldLinkStructure[]) + : [instance.common.welcomeScreenPro as OldLinkStructure]; _compatibilityStructureArr.forEach(compatibilityStructure => { if (compatibilityStructure.link) { @@ -1089,10 +1104,7 @@ class Intro extends React.Component { } if (compatibilityStructure.name) { - item.name = Intro.getText( - compatibilityStructure.name as ioBroker.StringOrTranslated, - language, - ); + item.name = Intro.getText(compatibilityStructure.name, language); } result.push(item); @@ -1112,7 +1124,6 @@ class Intro extends React.Component { // normalize icon item.icon = `adapter/${instance.common.name}/${item.icon}`; } - item.link = item.link.replace(/%ip%/g, '%web_bind%'); }); if (filterDuplicates) { @@ -1206,76 +1217,9 @@ class Intro extends React.Component { } const introInstances: IntroInstanceItem[] = []; const instances: Record = {}; + // Array to the mapped object objects.forEach(obj => (instances[obj._id] = obj)); - objects.sort((_a, _b) => { - const a: Partial = _a?.common ?? {}; - const b: Partial = _b?.common ?? {}; - - // @ts-expect-error need to be added to types if this can exist - if (a.order === undefined && b.order === undefined) { - let aName; - let bName; - if (typeof a.name === 'object') { - const commonNameA: ioBroker.Translated = a.name; - aName = commonNameA[this.props.lang] || commonNameA.en; - } else { - aName = a.name || ''; - } - if (typeof b.name === 'object') { - const commonNameB: ioBroker.Translated = b.name; - bName = commonNameB[this.props.lang] || commonNameB.en; - } else { - bName = b.name || ''; - } - if (aName.toLowerCase() > bName.toLowerCase()) { - return 1; - } - if (aName.toLowerCase() < bName.toLowerCase()) { - return -1; - } - return 0; - } - // @ts-expect-error need to be added to types if this can exist - if (a.order === undefined) { - return -1; - } - // @ts-expect-error need to be added to types if this can exist - if (b.order === undefined) { - return 1; - } - // @ts-expect-error need to be added to types if this can exist - if (a.order > b.order) { - return 1; - } - // @ts-expect-error need to be added to types if this can exist - if (a.order < b.order) { - return -1; - } - let aName: string; - if (typeof a.name === 'object') { - const commonNameA: ioBroker.Translated = a.name; - aName = commonNameA[this.props.lang] || commonNameA.en; - } else { - aName = a.name || ''; - } - - let bName; - if (typeof b.name === 'object') { - const commonNameB: ioBroker.Translated = b.name; - bName = commonNameB[this.props.lang] || commonNameB.en; - } else { - bName = b.name || ''; - } - if (aName.toLowerCase() > bName.toLowerCase()) { - return 1; - } - if (aName.toLowerCase() < bName.toLowerCase()) { - return -1; - } - return 0; - }); - objects.forEach(obj => { if (!obj) { return; @@ -1301,7 +1245,7 @@ class Intro extends React.Component { if (name && name !== 'vis-web-admin' && name.match(/^vis-/) && name !== 'vis-2') { return; } - if (name && name.match(/^icons-/)) { + if (name?.match(/^icons-/)) { return; } if (common && (common.enabled || common.onlyWWW)) { diff --git a/packages/admin/src-admin/src/tabs/Logs.tsx b/packages/admin/src-admin/src/tabs/Logs.tsx index dc42a4f2e..5004dfd92 100644 --- a/packages/admin/src-admin/src/tabs/Logs.tsx +++ b/packages/admin/src-admin/src/tabs/Logs.tsx @@ -61,7 +61,7 @@ import type LogsWorker from '@/Workers/LogsWorker'; import type { LogLineSaved } from '@/Workers/LogsWorker'; import type { CompactAdapterInfo, CompactHost } from '@/types'; -import AdminUtils from '../AdminUtils'; +import AdminUtils from '../helpers/AdminUtils'; const MAX_LOGS = 3000; diff --git a/packages/admin/src/i18n/de.json b/packages/admin/src/i18n/de.json new file mode 100644 index 000000000..710d6db38 --- /dev/null +++ b/packages/admin/src/i18n/de.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "Kennwort für „%s“ kann nicht geändert werden: %s", + "Cannot change password for %s:": "Das Passwort für den Benutzer „%s“ kann nicht geändert werden. Bitte versuchen Sie es manuell.\nÖffnen Sie die CLI, melden Sie sich als Benutzer mit Root-/Sudo-Rechten an und geben Sie ein:", + "Empty password isn't allowed": "Leeres Passwort ist nicht zulässig", + "Enter your new password by prompt.": "Geben Sie bei der entsprechenden Aufforderung Ihr neues Passwort ein.", + "Minimal length is 6 chars": "Die Mindestlänge beträgt 6 Zeichen", + "New password": "Neues Passwort", + "Offline message": "Anleitung zum Ändern des Passworts. Öffnen Sie die CLI, melden Sie sich als Benutzer mit Root-/Sudo-Rechten an und geben Sie ein:\n\n„sudo passwd %s“\nGeben Sie Ihr neues Passwort bei der Eingabeaufforderung ein.", + "Password and password repeat are not equal": "Passwort und Passwortwiederholung sind nicht gleich", + "Password is too short (min 6 chars)": "Das Passwort ist zu kurz (mindestens 6 Zeichen)", + "Password repeat": "Passwort wiederholen", + "Password successfully changed for \"%s\"": "Passwort für „%s“ erfolgreich geändert", + "Set password": "Passwort festlegen", + "The password for user \"%s\" was successfully changed": "Das Passwort für den Benutzer „%s“ wurde erfolgreich geändert", + "This message is no more actual and was generated by other instance start": "Diese Meldung ist nicht mehr aktuell und wurde beim Start einer anderen Instanz generiert.", + "User \"%s\" has well known password. We suggest to change it.": "Das Betriebssystem scheint ein bekanntes Standardpasswort für System-Benutzer \"%s\" zu nutzen. Aus Sicherheitsgründen empfehlen wir dies zu ändern.", + "User: %s": "Benutzer: %s" +} diff --git a/packages/admin/src/i18n/en.json b/packages/admin/src/i18n/en.json new file mode 100644 index 000000000..7eb3d8bb1 --- /dev/null +++ b/packages/admin/src/i18n/en.json @@ -0,0 +1,18 @@ +{ + "Offline message": "Instruction how to change password. Open CLI, login as user with root/sudo rights and enter:\n\"sudo passwd %s\"\nEnter your new password by prompt.", + "The password for user \"%s\" was successfully changed": "The password for user \"%s\" was successfully changed", + "Cannot change password for %s:": "The password for user \"%s\" cannot be changed. Please try to do it manually.\nOpen CLI, login as user with root/sudo rights and enter:", + "Enter your new password by prompt.": "Enter your new password by prompt.", + "User \"%s\" has well known password. We suggest to change it.": "The operating system appears to be using a well-known default password for system user \"%s\". For security reasons, we recommend changing it.", + "New password": "New password", + "Password repeat": "Password repeat", + "Set password": "Set password", + "This message is no more actual and was generated by other instance start": "This message is no more actual and was generated by other instance start", + "Empty password isn't allowed": "Empty password isn't allowed", + "Password and password repeat are not equal": "Password and password repeat are not equal", + "Password is too short (min 6 chars)": "Password is too short (min 6 chars)", + "Password successfully changed for \"%s\"": "Password successfully changed for \"%s\"", + "Cannot change password for \"%s\": %s": "Cannot change password for \"%s\": %s", + "Minimal length is 6 chars": "Minimal length is 6 chars", + "User: %s": "User: %s" +} diff --git a/packages/admin/src/i18n/es.json b/packages/admin/src/i18n/es.json new file mode 100644 index 000000000..7c54a60e9 --- /dev/null +++ b/packages/admin/src/i18n/es.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "No se puede cambiar la contraseña para \"%s\": %s", + "Cannot change password for %s:": "No se puede cambiar la contraseña del usuario \"%s\". Intente hacerlo manualmente.\nAbra la CLI, inicie sesión como usuario con derechos de root/sudo e ingrese:", + "Empty password isn't allowed": "No se permite contraseña vacía", + "Enter your new password by prompt.": "Ingrese su nueva contraseña cuando se le solicite.", + "Minimal length is 6 chars": "La longitud mínima es de 6 caracteres.", + "New password": "Nueva contraseña", + "Offline message": "Instrucciones sobre cómo cambiar la contraseña. Abra la CLI, inicie sesión como usuario con derechos de root/sudo e ingrese:\n\"sudo passwd %s\"\nIngrese su nueva contraseña cuando se le solicite.", + "Password and password repeat are not equal": "La contraseña y la repetición de contraseña no son iguales", + "Password is too short (min 6 chars)": "La contraseña es demasiado corta (mínimo 6 caracteres)", + "Password repeat": "Repetición de contraseña", + "Password successfully changed for \"%s\"": "La contraseña para \"%s\" se cambió correctamente", + "Set password": "Establecer contraseña", + "The password for user \"%s\" was successfully changed": "La contraseña del usuario \"%s\" se cambió correctamente", + "This message is no more actual and was generated by other instance start": "Este mensaje ya no es actual y fue generado por otra instancia de inicio.", + "User \"%s\" has well known password. We suggest to change it.": "El usuario \"%s\" tiene una contraseña conocida. Le sugerimos cambiarla.", + "User: %s": "Usuario: %s" +} \ No newline at end of file diff --git a/packages/admin/src/i18n/fr.json b/packages/admin/src/i18n/fr.json new file mode 100644 index 000000000..90be116fb --- /dev/null +++ b/packages/admin/src/i18n/fr.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "Impossible de changer le mot de passe pour « %s » : %s", + "Cannot change password for %s:": "Le mot de passe de l'utilisateur « %s » ne peut pas être modifié. Veuillez essayer de le faire manuellement.\nOuvrez la CLI, connectez-vous en tant qu'utilisateur avec les droits root/sudo et saisissez :", + "Empty password isn't allowed": "Un mot de passe vide n'est pas autorisé", + "Enter your new password by prompt.": "Entrez votre nouveau mot de passe lorsque vous y êtes invité.", + "Minimal length is 6 chars": "La longueur minimale est de 6 caractères", + "New password": "Nouveau mot de passe", + "Offline message": "Instructions pour changer le mot de passe. Ouvrez la CLI, connectez-vous en tant qu'utilisateur avec les droits root/sudo et saisissez :\n\"sudo passwd %s\"\nSaisissez votre nouveau mot de passe lorsque vous y êtes invité.", + "Password and password repeat are not equal": "Le mot de passe et la répétition du mot de passe ne sont pas égaux", + "Password is too short (min 6 chars)": "Le mot de passe est trop court (au moins 6 caractères)", + "Password repeat": "Répéter le mot de passe", + "Password successfully changed for \"%s\"": "Mot de passe modifié avec succès pour « %s »", + "Set password": "Définir un mot de passe", + "The password for user \"%s\" was successfully changed": "Le mot de passe de l'utilisateur « %s » a été modifié avec succès", + "This message is no more actual and was generated by other instance start": "Ce message n'est plus d'actualité et a été généré par une autre instance", + "User \"%s\" has well known password. We suggest to change it.": "L'utilisateur « %s » possède un mot de passe bien connu. Nous vous suggérons de le modifier.", + "User: %s": "Utilisateur : %s" +} \ No newline at end of file diff --git a/packages/admin/src/i18n/it.json b/packages/admin/src/i18n/it.json new file mode 100644 index 000000000..dfbbe0372 --- /dev/null +++ b/packages/admin/src/i18n/it.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "Impossibile modificare la password per \"%s\": %s", + "Cannot change password for %s:": "La password per l'utente \"%s\" non può essere modificata. Prova a farlo manualmente.\nApri CLI, accedi come utente con diritti root/sudo e inserisci:", + "Empty password isn't allowed": "Non è consentita la password vuota", + "Enter your new password by prompt.": "Inserisci la nuova password quando richiesto.", + "Minimal length is 6 chars": "La lunghezza minima è di 6 caratteri", + "New password": "Nuova password", + "Offline message": "Istruzioni su come cambiare password. Apri CLI, accedi come utente con diritti root/sudo e inserisci:\n\"sudo passwd %s\"\nInserisci la tua nuova password quando richiesto.", + "Password and password repeat are not equal": "La password e la ripetizione della password non sono uguali", + "Password is too short (min 6 chars)": "La password è troppo corta (min 6 caratteri)", + "Password repeat": "Ripetizione password", + "Password successfully changed for \"%s\"": "Password modificata con successo per \"%s\"", + "Set password": "Imposta password", + "The password for user \"%s\" was successfully changed": "La password per l'utente \"%s\" è stata modificata con successo", + "This message is no more actual and was generated by other instance start": "Questo messaggio non è più attuale ed è stato generato da un'altra istanza di avvio", + "User \"%s\" has well known password. We suggest to change it.": "L'utente \"%s\" ha una password ben nota. Ti consigliamo di cambiarla.", + "User: %s": "Utente: %s" +} \ No newline at end of file diff --git a/packages/admin/src/i18n/nl.json b/packages/admin/src/i18n/nl.json new file mode 100644 index 000000000..9825b1bbf --- /dev/null +++ b/packages/admin/src/i18n/nl.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "Kan wachtwoord voor \"%s\" niet wijzigen: %s", + "Cannot change password for %s:": "Het wachtwoord voor gebruiker \"%s\" kan niet worden gewijzigd. Probeer het handmatig.\nOpen CLI, log in als gebruiker met root/sudo-rechten en voer in:", + "Empty password isn't allowed": "Een leeg wachtwoord is niet toegestaan", + "Enter your new password by prompt.": "Voer uw nieuwe wachtwoord in als daarom wordt gevraagd.", + "Minimal length is 6 chars": "Minimale lengte is 6 tekens", + "New password": "Nieuw wachtwoord", + "Offline message": "Instructies voor het wijzigen van het wachtwoord. Open CLI, log in als gebruiker met root/sudo rechten en voer in:\n\"sudo passwd %s\"\nVoer uw nieuwe wachtwoord in bij de prompt.", + "Password and password repeat are not equal": "Wachtwoord en wachtwoordherhaling zijn niet gelijk", + "Password is too short (min 6 chars)": "Wachtwoord is te kort (minimaal 6 tekens)", + "Password repeat": "Wachtwoord herhalen", + "Password successfully changed for \"%s\"": "Wachtwoord succesvol gewijzigd voor \"%s\"", + "Set password": "Wachtwoord instellen", + "The password for user \"%s\" was successfully changed": "Het wachtwoord voor gebruiker \"%s\" is succesvol gewijzigd", + "This message is no more actual and was generated by other instance start": "Dit bericht is niet meer actueel en is gegenereerd door een ander exemplaar", + "User \"%s\" has well known password. We suggest to change it.": "Gebruiker \"%s\" heeft een bekend wachtwoord. Wij raden aan om dit te wijzigen.", + "User: %s": "Gebruiker: %s" +} \ No newline at end of file diff --git a/packages/admin/src/i18n/pl.json b/packages/admin/src/i18n/pl.json new file mode 100644 index 000000000..e0b41861e --- /dev/null +++ b/packages/admin/src/i18n/pl.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "Nie można zmienić hasła dla „%s”: %s", + "Cannot change password for %s:": "Hasła użytkownika „%s” nie można zmienić. Spróbuj zrobić to ręcznie.\nOtwórz CLI, zaloguj się jako użytkownik z uprawnieniami root/sudo i wprowadź:", + "Empty password isn't allowed": "Puste hasło nie jest dozwolone", + "Enter your new password by prompt.": "Wprowadź nowe hasło po wyświetleniu monitu.", + "Minimal length is 6 chars": "Minimalna długość to 6 znaków", + "New password": "Nowe hasło", + "Offline message": "Instrukcja zmiany hasła. Otwórz CLI, zaloguj się jako użytkownik z uprawnieniami root/sudo i wpisz:\n\"sudo passwd %s\"\nWprowadź nowe hasło po wyświetleniu monitu.", + "Password and password repeat are not equal": "Hasło i powtórzenie hasła nie są równe", + "Password is too short (min 6 chars)": "Hasło jest za krótkie (min. 6 znaków)", + "Password repeat": "Powtórz hasło", + "Password successfully changed for \"%s\"": "Hasło dla \"%s\" zostało pomyślnie zmienione", + "Set password": "Ustaw hasło", + "The password for user \"%s\" was successfully changed": "Hasło użytkownika „%s” zostało pomyślnie zmienione", + "This message is no more actual and was generated by other instance start": "Ta wiadomość nie jest już aktualna i została wygenerowana przez uruchomienie innej instancji", + "User \"%s\" has well known password. We suggest to change it.": "Użytkownik \"%s\" ma dobrze znane hasło. Sugerujemy jego zmianę.", + "User: %s": "Użytkownik: %s" +} \ No newline at end of file diff --git a/packages/admin/src/i18n/pt.json b/packages/admin/src/i18n/pt.json new file mode 100644 index 000000000..d588dab7c --- /dev/null +++ b/packages/admin/src/i18n/pt.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "Não é possível alterar a senha para \"%s\": %s", + "Cannot change password for %s:": "A senha do usuário \"%s\" não pode ser alterada. Tente fazer isso manualmente.\nAbra o CLI, faça login como usuário com direitos root/sudo e digite:", + "Empty password isn't allowed": "Não é permitida uma senha vazia", + "Enter your new password by prompt.": "Digite sua nova senha quando solicitado.", + "Minimal length is 6 chars": "O comprimento mínimo é de 6 caracteres", + "New password": "Nova Senha", + "Offline message": "Instruções sobre como alterar a senha. Abra o CLI, faça login como usuário com direitos root/sudo e digite:\n\"sudo passwd %s\"\nDigite sua nova senha por prompt.", + "Password and password repeat are not equal": "Senha e repetição de senha não são iguais", + "Password is too short (min 6 chars)": "A senha é muito curta (mínimo de 6 caracteres)", + "Password repeat": "Repetição de senha", + "Password successfully changed for \"%s\"": "A senha foi alterada com sucesso para \"%s\"", + "Set password": "Definir senha", + "The password for user \"%s\" was successfully changed": "A senha do usuário \"%s\" foi alterada com sucesso", + "This message is no more actual and was generated by other instance start": "Esta mensagem não é mais atual e foi gerada por outra instância inicial", + "User \"%s\" has well known password. We suggest to change it.": "O usuário \"%s\" tem uma senha bem conhecida. Sugerimos alterá-la.", + "User: %s": "Usuários" +} \ No newline at end of file diff --git a/packages/admin/src/i18n/ru.json b/packages/admin/src/i18n/ru.json new file mode 100644 index 000000000..0069f347f --- /dev/null +++ b/packages/admin/src/i18n/ru.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "Невозможно изменить пароль для \"%s\": %s", + "Cannot change password for %s:": "Пароль пользователя \"%s\" не может быть изменен. Попробуйте сделать это вручную.\nОткройте CLI, войдите как пользователь с правами root/sudo и введите:", + "Empty password isn't allowed": "Пустой пароль не допускается.", + "Enter your new password by prompt.": "Введите новый пароль по запросу.", + "Minimal length is 6 chars": "Минимальная длина — 6 символов.", + "New password": "Новый пароль", + "Offline message": "Инструкция по смене пароля. Откройте CLI, войдите как пользователь с правами root/sudo и введите:\n\"sudo passwd %s\"\nВведите новый пароль по запросу.", + "Password and password repeat are not equal": "Пароль и повтор пароля не равны", + "Password is too short (min 6 chars)": "Пароль слишком короткий (минимум 6 символов)", + "Password repeat": "Повторите пароль", + "Password successfully changed for \"%s\"": "Пароль успешно изменен для \"%s\"", + "Set password": "Установить пароль", + "The password for user \"%s\" was successfully changed": "Пароль для пользователя \"%s\" был успешно изменен", + "This message is no more actual and was generated by other instance start": "Это сообщение больше не актуально и было сгенерировано при запуске другого экземпляра", + "User \"%s\" has well known password. We suggest to change it.": "Операционная система, похоже, использует известный стандартный пароль для системного пользователя \"%s\". В целях безопасности мы рекомендуем его изменить.", + "User: %s": "Пользователь: %s" +} diff --git a/packages/admin/src/i18n/uk.json b/packages/admin/src/i18n/uk.json new file mode 100644 index 000000000..066a36159 --- /dev/null +++ b/packages/admin/src/i18n/uk.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "Неможливо змінити пароль для \"%s\": %s", + "Cannot change password for %s:": "Пароль користувача \"%s\" не можна змінити. Будь ласка, спробуйте зробити це вручну.\nВідкрийте CLI, увійдіть як користувач із правами root/sudo та введіть:", + "Empty password isn't allowed": "Порожній пароль заборонено", + "Enter your new password by prompt.": "Введіть свій новий пароль після підказки.", + "Minimal length is 6 chars": "Мінімальна довжина – 6 символів", + "New password": "Новий пароль", + "Offline message": "Інструкція як змінити пароль. Відкрийте CLI, увійдіть як користувач із правами root/sudo та введіть:\n\"sudo passwd %s\"\nВведіть свій новий пароль після підказки.", + "Password and password repeat are not equal": "Пароль і повтор пароля не однакові", + "Password is too short (min 6 chars)": "Пароль занадто короткий (мінімум 6 символів)", + "Password repeat": "Повторення пароля", + "Password successfully changed for \"%s\"": "Пароль для \"%s\" успішно змінено", + "Set password": "Встановити пароль", + "The password for user \"%s\" was successfully changed": "Пароль користувача \"%s\" успішно змінено", + "This message is no more actual and was generated by other instance start": "Це повідомлення більше не є актуальним і було згенероване запуском іншого екземпляра", + "User \"%s\" has well known password. We suggest to change it.": "Користувач \"%s\" має добре відомий пароль. Пропонуємо змінити.", + "User: %s": "Користувач: %s" +} \ No newline at end of file diff --git a/packages/admin/src/i18n/zh-cn.json b/packages/admin/src/i18n/zh-cn.json new file mode 100644 index 000000000..edeb7d002 --- /dev/null +++ b/packages/admin/src/i18n/zh-cn.json @@ -0,0 +1,18 @@ +{ + "Cannot change password for \"%s\": %s": "无法更改“%s”的密码:%s", + "Cannot change password for %s:": "无法更改用户“%s”的密码。请尝试手动更改。\n打开 CLI,以具有 root/sudo 权限的用户身份登录并输入:", + "Empty password isn't allowed": "不允许使用空密码", + "Enter your new password by prompt.": "根据提示输入您的新密码。", + "Minimal length is 6 chars": "最小长度为 6 个字符", + "New password": "新密码", + "Offline message": "更改密码的说明。打开 CLI,以具有 root/sudo 权限的用户身份登录并输入:\n“sudo passwd %s”\n根据提示输入新密码。", + "Password and password repeat are not equal": "密码与密码重复不相等", + "Password is too short (min 6 chars)": "密码太短(至少 6 个字符)", + "Password repeat": "密码重复", + "Password successfully changed for \"%s\"": "已成功更改“%s”的密码", + "Set password": "设置密码", + "The password for user \"%s\" was successfully changed": "用户“%s”的密码已成功更改", + "This message is no more actual and was generated by other instance start": "此消息不再是实际消息并且是由其他实例启动生成的", + "User \"%s\" has well known password. We suggest to change it.": "用户“%s”的密码众所周知。我们建议更改它。", + "User: %s": "用户:%s" +} \ No newline at end of file diff --git a/packages/admin/src/lib/checkLinuxPass.ts b/packages/admin/src/lib/checkLinuxPass.ts new file mode 100644 index 000000000..0e1fe6c51 --- /dev/null +++ b/packages/admin/src/lib/checkLinuxPass.ts @@ -0,0 +1,225 @@ +import { spawn } from 'child_process'; + +const WELL_KNOWN_CREDENTIALS = [ + ['root', 'root'], + ['admin', 'admin'], + ['admin', 'default'], + ['root', 'default'], + ['iob', '2024=smart!'], + ['pi', 'pi'], + ['pi', '12345'], + ['pi', 'raspberry'], + ['pi', 'default'], + ['pi', 'pi12345'], +]; + +// Function to execute 'su' command and provide password +function checkLinuxPassword(login: string, password: string): Promise { + // Check the os + if (process.platform !== 'linux') { + console.error('This function is only available on Linux'); + return Promise.resolve(false); + } + + if (login === 'Password:' || login === 'failure') { + console.error('This function requires a login name'); + return Promise.resolve(false); + } + console.log(`\n[LOG] -------- Check ${login}/${password}`); + + return new Promise((resolve, reject) => { + try { + const su = spawn('su', [login]); + let result = false; + let responseTimeout = setTimeout(() => { + responseTimeout = null; + su.kill(); + }, 3000); + + function _checkPassword(data: string): void { + data = data.replace(/\r/g, ' ').replace(/\n/g, ' ').trim(); + console.log(`[STDX] "${data}"`); + if (data.endsWith(':')) { + su.stdin.write(`${password}\n`); + setTimeout(() => { + console.log(`[LOG] write whoami`); + su.stdin.write(`whoami\n`); + }, 50); + } else if (data === login) { + result = true; + su.kill(); + // todo: add ru, uk, pt,.... + } else if (data.toLowerCase().includes('failure') || data.toLowerCase().includes('fehler')) { + su.kill(); + } + } + + // Listen for data on stdout + su.stdout.on('data', data => _checkPassword(data.toString())); + + // Listen for data on stderr + su.stderr.on('data', data => _checkPassword(data.toString())); + + // Listen for the close event + su.on('close', () => { + console.log(`[LOG] -------- closed with result: ${result}\n`); + responseTimeout && clearTimeout(responseTimeout); + responseTimeout = null; + resolve(result); + }); + } catch (e: any) { + console.error(`[LOG] -------- Error by execution: ${e.message}\n`); + reject(new Error(e)); + } + }); +} + +/** Check if the system has well-known passwords */ +export async function checkWellKnownPasswords(): Promise<{ login: string; password: string } | null> { + // Check the os + if (process.platform !== 'linux') { + console.error('This function is only available on Linux'); + throw new Error('This function is only available on Linux'); + } + for (const [login, password] of WELL_KNOWN_CREDENTIALS) { + if (await checkLinuxPassword(login, password)) { + return { login, password }; + } + } + return null; +} + +/* +pi@NanoPi-R5S:/opt$ su pi +Password: [OLD PASSWORD]\n + +pi@NanoPi-R5S:/opt$ passwd +Changing password for pi. +Current password: [OLD PASSWORD]\n + +New password: [NEW PASSWORD]\n + +Retype new password: [NEW PASSWORD]\n + +The password has not been changed. + +New password: +Retype new password: + +You must choose a longer password. + +New password: +Retype new password: + +passwd: password updated successfully +pi@NanoPi-R5S:/opt$ exit +*/ + +/* +Ändern des Passworts für pi. +Geben Sie das aktuelle Passwort ein: +passwd: Fehler beim Ändern des Authentifizierungstoken +passwd: Passwort nicht geändert +pi@NanoPi-R5S:~$ passwd pi +Ändern des Passworts für pi. +Geben Sie das aktuelle Passwort ein: +Geben Sie ein neues Passwort ein: +Geben Sie das neue Passwort erneut ein: +passwd: Passwort erfolgreich geändert + + */ +const STATES = { + S_0_SU_WAIT_PROMPT: 0, + S_1_PASSWD_WAIT_PROMPT_CURRENT_PASSWORD: 1, + S_2_PASSWD_WAIT_PROMPT_NEW_PASSWORD: 2, + S_3_PASSWD_WAIT_PROMPT_RETYPE_NEW_PASSWORD: 3, + S_4_PASSWD_WAIT_RESPONSE: 4, +}; + +export function setLinuxPassword(login: string, oldPassword: string, newPassword: string): Promise { + return new Promise(resolve => { + if (WELL_KNOWN_CREDENTIALS.find(item => item[0] === newPassword || item[1] === newPassword)) { + resolve('New password is well-known too'); + return; + } + try { + const su = spawn('su', [login]); + let result: true | string = 'Cannot change password'; + let responseTimeout = setTimeout(() => { + responseTimeout = null; + result = 'Timeout'; + su.kill(); + }, 3000); + + let state = STATES.S_0_SU_WAIT_PROMPT; + + function _checkPassword(data: string): void { + data = data.replace(/\r/g, ' ').replace(/\n/g, ' ').trim(); + console.log(`[STDX]: ${data}`); + if (state === STATES.S_0_SU_WAIT_PROMPT) { + // Password: [OLD PASSWORD]\n + if (data.endsWith(':')) { + console.log(`[LOG]: received request to enter old password`); + su.stdin.write(`${oldPassword}\n`); + setTimeout(() => { + state = STATES.S_1_PASSWD_WAIT_PROMPT_CURRENT_PASSWORD; + su.stdin.write(`passwd\n`); + }, 50); + // todo: add ru, uk, pt,.... + } else if (data.toLowerCase().includes('failure') || data.toLowerCase().includes('fehler')) { + console.log(`[LOG]: received failure message`); + result = 'Old password not accepted'; + su.kill(); + } + } else if (state === STATES.S_1_PASSWD_WAIT_PROMPT_CURRENT_PASSWORD) { + // Changing password for pi. + // Current password: [OLD PASSWORD]\n + if (data.endsWith(':')) { + console.log(`[LOG]: received request to enter new password`); + state = STATES.S_2_PASSWD_WAIT_PROMPT_NEW_PASSWORD; + su.stdin.write(`${oldPassword}\n`); + } + } else if (state === STATES.S_2_PASSWD_WAIT_PROMPT_NEW_PASSWORD) { + // New password: [NEW PASSWORD]\n + if (data.endsWith(':')) { + console.log(`[LOG]: received request to enter new password`); + state = STATES.S_3_PASSWD_WAIT_PROMPT_RETYPE_NEW_PASSWORD; + su.stdin.write(`${newPassword}\n`); + } + } else if (state === STATES.S_3_PASSWD_WAIT_PROMPT_RETYPE_NEW_PASSWORD) { + // Retype new password: [NEW PASSWORD]\n + if (data.endsWith(':')) { + console.log(`[LOG]: received request to repeat new password`); + state = STATES.S_4_PASSWD_WAIT_RESPONSE; + su.stdin.write(`${newPassword}\n`); + } + } else if (state === STATES.S_4_PASSWD_WAIT_RESPONSE) { + // todo: add ru, uk, pt,.... + if (data.toLowerCase().includes('successfully') || data.toLowerCase().includes('erfolgreich')) { + result = true; + } else { + // failure + result = data; + } + su.kill(); + } + } + + // Listen for data on stdout + su.stdout.on('data', data => _checkPassword(data.toString())); + + // Listen for data on stderr + su.stderr.on('data', data => _checkPassword(data.toString())); + + // Listen for the close event + su.on('close', () => { + responseTimeout && clearTimeout(responseTimeout); + responseTimeout = null; + resolve(result); + }); + } catch (e) { + console.error(`Cannot change password: ${e.toString()}`); + throw new Error(e); + } + }); +} diff --git a/packages/admin/src/lib/testPassword.ts b/packages/admin/src/lib/testPassword.ts new file mode 100644 index 000000000..7570e431b --- /dev/null +++ b/packages/admin/src/lib/testPassword.ts @@ -0,0 +1,54 @@ +import { createInterface } from 'node:readline'; +import { setLinuxPassword, checkWellKnownPasswords } from './checkLinuxPass'; +import { Writable } from 'node:stream'; + +let maskOutput = false; +// this file is used for test on different locales +// node /opt/iobroker/node_modules/iobroker.admin/build-backend/lib/testPassword +const mutableStdout = new Writable({ + write: (_chunk, _encoding, callback) => { + if (maskOutput) { + process.stdout.write('*'); + } else { + process.stdout.write(_chunk, _encoding); + } + callback(); + }, +}); + +checkWellKnownPasswords().then(found => { + if (found) { + console.log(`Found well-known password: ${JSON.stringify(found)}`); + // enter new password + const rl = createInterface({ + input: process.stdin, + output: mutableStdout, + terminal: true, + }); + rl.question(`Enter new password for "${found.login} (min 6 chars): `, (password: string) => { + maskOutput = false; + password = password.replace(/\r/g, '').replace(/\n/g, ''); + if (password.length < 6) { + console.error('password is too short'); + process.exit(1); + } + rl.question(`Repeat new password for "${found.login}: `, (passwordRepeat: string) => { + maskOutput = false; + passwordRepeat = passwordRepeat.replace(/\r/g, '').replace(/\n/g, ''); + if (password !== passwordRepeat) { + console.error('passwords are not equal'); + process.exit(1); + } + rl.close(); + void setLinuxPassword(found.login, found.password, password).then(result => { + console.log(`Result: ${JSON.stringify(result)}`); + }); + }); + maskOutput = true; + }); + maskOutput = true; + } else { + console.log(`No well known passwords found`); + process.exit(0); + } +}); diff --git a/packages/admin/src/lib/utils.ts b/packages/admin/src/lib/utils.ts new file mode 100644 index 000000000..6504ee8b6 --- /dev/null +++ b/packages/admin/src/lib/utils.ts @@ -0,0 +1,441 @@ +/** Url where controller changelog is reachable */ +export const CONTROLLER_CHANGELOG_URL = 'https://github.com/ioBroker/ioBroker.js-controller/blob/master/CHANGELOG.md'; + +/** All possible auto upgrade settings */ +export const AUTO_UPGRADE_SETTINGS: ioBroker.AutoUpgradePolicy[] = ['none', 'patch', 'minor', 'major']; + +/** Mapping to make it more understandable which upgrades are allowed */ +export const AUTO_UPGRADE_OPTIONS_MAPPING: Record = { + none: 'none', + patch: 'patch', + minor: 'patch & minor', + major: 'patch, minor & major', +}; + +function ip2int(ip: string): number { + return ip.split('.').reduce((ipInt, octet) => (ipInt << 8) + parseInt(octet, 10), 0) >>> 0; +} + +function findNetworkAddressOfHost(obj: ioBroker.HostObject, localIp: string): null | string { + const networkInterfaces = obj?.native?.hardware?.networkInterfaces; + if (!networkInterfaces) { + return null; + } + + let hostIp; + for (const networkInterface of Object.values(networkInterfaces)) { + if (!networkInterface) { + continue; + } + for (let i = 0; i < networkInterface.length; i++) { + const ip = networkInterface[i]; + if (ip.internal) { + return; + } + if (localIp.includes(':') && ip.family !== 'IPv6') { + return; + } + if (localIp.includes('.') && !localIp.match(/[^.\d]/) && ip.family !== 'IPv4') { + return; + } + if (localIp === '127.0.0.0' || localIp === 'localhost' || localIp.match(/[^.\d]/)) { + // if DNS name + hostIp = ip.address; + } else if ( + ip.family === 'IPv4' && + localIp.includes('.') && + (ip2int(localIp) & ip2int(ip.netmask)) === (ip2int(ip.address) & ip2int(ip.netmask)) + ) { + hostIp = ip.address; + } else { + hostIp = ip.address; + } + } + } + + if (!hostIp) { + for (const networkInterface of Object.values(networkInterfaces)) { + if (!networkInterface) { + continue; + } + for (let i = 0; i < networkInterface.length; i++) { + const ip = networkInterface[i]; + if (ip.internal) { + return; + } + if (localIp.includes(':') && ip.family !== 'IPv6') { + return; + } + if (localIp.includes('.') && !localIp.match(/[^.\d]/) && ip.family !== 'IPv4') { + return; + } + if (localIp === '127.0.0.0' || localIp === 'localhost' || localIp.match(/[^.\d]/)) { + // if DNS name + hostIp = ip.address; + } else { + hostIp = ip.address; + } + } + } + } + + if (!hostIp) { + for (const networkInterface of Object.values(networkInterfaces)) { + if (!networkInterface) { + continue; + } + for (let i = 0; i < networkInterface.length; i++) { + const ip = networkInterface[i]; + if (ip.internal) { + return; + } + hostIp = ip.address; + } + } + } + + return hostIp; +} + +function getHostname( + instanceObj: ioBroker.InstanceObject, + objects: Record, + hosts: Record, + currentHostname: string, + adminInstance: string, +): string { + if (!instanceObj || !instanceObj.common) { + return null; + } + + let hostname; + // check if the adapter from the same host as admin + const adminHost = objects[`system.adapter.${adminInstance}`]?.common?.host; + if (instanceObj.common.host !== adminHost) { + // find IP address + const host = hosts[`system.host.${instanceObj.common.host}`]; + if (host) { + const ip = findNetworkAddressOfHost(host, currentHostname); + if (ip) { + hostname = ip; + } else { + console.warn(`Cannot find suitable IP in host ${instanceObj.common.host} for ${instanceObj._id}`); + return null; + } + } else { + console.warn(`Cannot find host ${instanceObj.common.host} for ${instanceObj._id}`); + return null; + } + } else { + hostname = currentHostname; + } + + return hostname; +} + +// internal use +function _replaceLink( + link: string, + objects: Record, + adapterInstance: string, + attr: string, + placeholder: string, + hosts: Record, + hostname: string, + adminInstance: string, +): string { + if (attr === 'protocol') { + attr = 'secure'; + } + + try { + const object = objects[`system.adapter.${adapterInstance}`]; + + if (link && object) { + if (attr === 'secure') { + link = link.replace(`%${placeholder}%`, object.native[attr] ? 'https' : 'http'); + } else { + let value = object.native[attr]; + // workaround for port + if ((attr === 'webinterfacePort' || attr === 'port') && (!value || value === '0')) { + if (object.native.secure === true) { + value = 443; + } else { + value = 80; + } + } + + if (attr === 'bind' || attr === 'ip') { + let ip = object.native.bind || object.native.ip; + if (ip === '0.0.0.0') { + ip = getHostname(object, objects, hosts, hostname, adminInstance); + } + if (!link.includes(`%${placeholder}%`)) { + link = link.replace(`%native_${placeholder}%`, ip || ''); + } else { + link = link.replace(`%${placeholder}%`, ip || ''); + } + } else if (!link.includes(`%${placeholder}%`)) { + link = link.replace(`%native_${placeholder}%`, value); + } else { + link = link.replace(`%${placeholder}%`, value); + } + } + } else { + console.log(`Cannot get link ${attr}`); + link = link.replace(`%${placeholder}%`, ''); + } + } catch (error) { + console.log(error); + } + return link; +} + +/** + * Convert the template link to string + * + * Possible placeholders: + * `%ip%` - `native.bind` or `native.ip` of this adapter. If it is '0.0.0.0', we are trying to find the host IP that is reachable from the current browser. + * `%protocol%` - `native.protocol` or `native.secure` of this adapter. The result is 'http' or 'https'. + * `%s%` - `native.protocol` or `native.secure` of this adapter. The result is '' or 's'. The idea is to use the pattern like "http%s%://..." + * `%instance%` - instance number + * `%adapterName_nativeAttr%` - Takes the native value `nativeAttr` of all instances of adapterName. This generates many links if more than one instance installed + * `%adapterName.x_nativeAttr%` - Takes the native value `nativeAttr` of adapterName.x instance + * + * @param link pattern for link + * @param adapter adapter name + * @param instance adapter instance number + * @param context Context object + * @param context.instances Object with all instances + * @param context.hostname Actual host name + * @param context.adminInstance Actual admin instance + * @param context.hosts Object with all hosts + */ +export function replaceLink( + link: string, + adapter: string, + instance: number, + context: { + instances: Record; + hostname: string; + adminInstance: string; + hosts: Record; + }, +): { + url: string; + port: number; + instance?: string; +}[] { + const _urls: { + url: string; + port: number; + instance?: string; + }[] = []; + let port: number; + + if (link) { + const instanceObj = context.instances[`system.adapter.${adapter}.${instance}`]; + const native = instanceObj?.native || {}; + + const placeholders = link.match(/%(\w+)%/g); + + if (placeholders) { + for (let p = 0; p < placeholders.length; p++) { + let placeholder = placeholders[p]; + + if (placeholder === '%ip%') { + let ip: string = (native.bind || native.ip) as string; + if (!ip || ip === '0.0.0.0') { + // Check host + ip = getHostname( + instanceObj, + context.instances, + context.hosts, + context.hostname, + context.adminInstance, + ); + } + + if (_urls.length) { + _urls.forEach(item => (item.url = item.url.replace('%ip%', ip))); + } else { + link = link.replace('%ip%', ip || ''); + } + } else if (placeholder === '%protocol%') { + const protocolVal: string | boolean = native.secure === undefined ? native.protocol : native.secure; + let protocol: 'http' | 'https'; + if (protocolVal === true || protocolVal === 'true') { + protocol = 'https'; + } else if (protocolVal === false || protocolVal === 'false' || !protocolVal) { + protocol = 'http'; + } else { + protocol = protocolVal.toString().replace(/:$/, '') as 'http' | 'https'; + } + + if (_urls.length) { + _urls.forEach(item => (item.url = item.url.replace('%protocol%', protocol))); + } else { + link = link.replace('%protocol%', protocol); + } + } else if (placeholder === '%s%') { + const protocolVal: string | boolean = native.secure === undefined ? native.protocol : native.secure; + let protocol: '' | 's'; + if (protocolVal === true || protocolVal === 'true') { + protocol = 's'; + } else if (protocolVal === false || protocolVal === 'false' || !protocolVal) { + protocol = ''; + } else { + protocol = protocolVal.toString().replace(/:$/, '') as '' | 's'; + } + + if (_urls.length) { + _urls.forEach(item => (item.url = item.url.replace('%s%', protocol))); + } else { + link = link.replace('%s%', protocol); + } + } else if (placeholder === '%instance%') { + link = link.replace('%instance%', instance.toString()); + if (_urls.length) { + _urls.forEach(item => (item.url = item.url.replace('%instance%', instance.toString()))); + } else { + link = link.replace('%instance%', instance.toString()); + } + } else { + // remove %% + placeholder = placeholder.replace(/%/g, ''); + + if (placeholder.startsWith('native_')) { + placeholder = placeholder.substring(7); + } + + // like web.0_port or web_protocol + if (!placeholder.includes('_')) { + // if only one instance + const adapterInstance = `${adapter}.${instance}`; + if (_urls.length) { + _urls.forEach( + item => + (item.url = _replaceLink( + item.url, + context.instances, + adapterInstance, + placeholder, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + )), + ); + } else { + link = _replaceLink( + link, + context.instances, + adapterInstance, + placeholder, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + port = context.instances[`system.adapter.${adapterInstance}`]?.native?.port; + } + } else { + const [adapterInstance, attr] = placeholder.split('_'); + + // if instance number not found + if (!adapterInstance.match(/\.[0-9]+$/)) { + // list all possible instances + let ids: string[]; + if (adapter === adapterInstance) { + // take only this one instance and that's all + ids = [`${adapter}.${instance}`]; + } else { + ids = Object.keys(context.instances) + .filter( + id => + id.startsWith(`system.adapter.${adapterInstance}.`) && + context.instances[id].common.enabled, + ) + .map(id => id.substring(15)); + + // try to get disabled instances + if (!ids.length) { + ids = Object.keys(context.instances) + .filter(id => id.startsWith(`system.adapter.${adapterInstance}.`)) + .map(id => id.substring(15)); + } + } + + for (const id of ids) { + if (_urls.length) { + const item = _urls.find(t => t.instance === id); + if (item) { + item.url = _replaceLink( + item.url, + context.instances, + id, + attr, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + } else { + // add new + const _link = _replaceLink( + link, + context.instances, + id, + attr, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + const _port: number = context.instances[`system.adapter.${id}`]?.native + ?.port as number; + + _urls.push({ url: _link, port: _port, instance: id }); + } + } else { + const _link = _replaceLink( + link, + context.instances, + id, + attr, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + + const _port: number = context.instances[`system.adapter.${id}`]?.native + ?.port as number; + _urls.push({ url: _link, port: _port, instance: id }); + } + } + } else { + link = _replaceLink( + link, + context.instances, + adapterInstance, + attr, + placeholder, + context.hosts, + context.hostname, + context.adminInstance, + ); + + port = context.instances[`system.adapter.${adapterInstance}`]?.native?.port as number; + } + } + } + } + } + } + + if (_urls.length) { + return _urls; + } + return [{ url: link, port }]; +} diff --git a/packages/admin/src/lib/web.ts b/packages/admin/src/lib/web.ts index 9f67ca402..2b8b6ac00 100644 --- a/packages/admin/src/lib/web.ts +++ b/packages/admin/src/lib/web.ts @@ -1,6 +1,7 @@ import * as utils from '@iobroker/adapter-core'; import * as IoBWebServer from '@iobroker/webserver'; import * as express from 'express'; +import { type RequestHandler } from 'express'; import * as fs from 'node:fs'; import * as util from 'util'; import * as path from 'node:path'; @@ -20,7 +21,6 @@ import type { Store } from 'express-session'; import * as session from 'express-session'; import * as bodyParser from 'body-parser'; import * as cookieParser from 'cookie-parser'; -import { type RequestHandler } from 'express'; interface IConnectFlashOptions { unsafe?: boolean | undefined; @@ -896,7 +896,7 @@ class Web { if (filename.startsWith(logFolder) && fs.existsSync(filename)) { const stat = fs.lstatSync(filename); - // if file is archive + // if a file is an archive if (filename.toLowerCase().endsWith('.gz')) { // try to not process to big files if (stat.size > 1024 * 1024 /* || !fs.existsSync('/dev/null')*/) { @@ -1152,7 +1152,19 @@ class Web { if (await this.adapter.fileExists(adapterName, url)) { const { mimeType, file } = await this.adapter.readFileAsync(adapterName, url); - res.contentType(mimeType || 'text/javascript'); + // special case for svg stored into logo.png + if (url.endsWith('.png') && file.length < 30000) { + const str = file.toString('utf8'); + if (str.startsWith(' = {}) { + private changedPasswords: WellKnownUserPassword[] = []; + + constructor(options: Partial = {}) { options = { ...options, name: adapterName, // adapter name @@ -102,7 +112,7 @@ class Admin extends utils.Adapter { install: () => void null, }; - super(options as utils.AdapterOptions); + super(options as AdapterOptions); this.on('objectChange', this.onObjectChange.bind(this)); this.on('stateChange', this.onStateChange.bind(this)); @@ -182,9 +192,10 @@ class Admin extends utils.Adapter { } else if (systemConfig.common?.language) { systemLanguage = systemConfig.common.language; } + I18n.init(__dirname, systemLanguage).catch(e => this.log.error(`Cannot init i18n: ${e}`)); if (!systemConfig.native.secret) { - crypto.randomBytes(24, (_ex, buf) => { + randomBytes(24, (_ex, buf) => { this.secret = buf.toString('hex'); this.extendForeignObject('system.config', { native: { secret: this.secret } }); this.init(); @@ -217,7 +228,7 @@ class Admin extends utils.Adapter { try { return ( obj.callback && - this.sendTo(obj.from, obj.command, { result: fs.existsSync(obj.message) }, obj.callback) + this.sendTo(obj.from, obj.command, { result: existsSync(obj.message) }, obj.callback) ); } catch (e) { return obj.callback && this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback); @@ -226,7 +237,7 @@ class Admin extends utils.Adapter { const result: Record = {}; for (let f = 0; f < obj.message.length; f++) { try { - result[obj.message[f]] = fs.existsSync(obj.message[f]); + result[obj.message[f]] = existsSync(obj.message[f]); } catch (e) { result[obj.message[f]] = e.message; } @@ -270,6 +281,8 @@ class Admin extends utils.Adapter { obj.callback && this.sendTo(obj.from, obj.command, { openUrl: obj.message._origin, saveConfig: true }, obj.callback) ); + } else if (obj.command.startsWith('admin:')) { + return this.processNotificationsGui(obj); } if (socket) { @@ -277,6 +290,210 @@ class Admin extends utils.Adapter { } } + processNotificationsGui(obj: ioBroker.Message): void { + if (obj.command === 'admin:getNotificationSchema') { + const guiMessage: { login: string; password: string } = obj.message; + const alreadyDone = this.changedPasswords.find( + item => item.login === guiMessage.login && item.password === guiMessage.password, + ); + let schema: any; + if (alreadyDone?.result === true) { + schema = { + type: 'panel', + items: { + _info: { + type: 'staticText', + text: I18n.getTranslatedObject( + 'The password for user "%s" was successfully changed', + guiMessage.login, + ), + style: { color: 'green' }, + sm: 12, + }, + }, + }; + } else if (alreadyDone?.result === false) { + schema = { + type: 'panel', + items: { + _info: { + type: 'staticText', + text: I18n.getTranslatedObject('Cannot change password for %s:', guiMessage.login), + style: { color: 'orange' }, + sm: 12, + }, + _info1: { + newLine: true, + type: 'staticText', + text: `sudo passwd ${guiMessage.login}`, + style: { fontFamilies: 'monospace', color: 'green', backgroundColor: 'black' }, + sm: 12, + }, + _info3: { + newLine: true, + type: 'staticText', + text: I18n.getTranslatedObject('Enter your new password by prompt.'), + style: { fontFamilies: 'monospace', color: 'green', backgroundColor: 'black' }, + sm: 12, + }, + }, + }; + } else if (alreadyDone) { + // Ask user for new password and for password repeat + schema = { + type: 'panel', + items: { + _info: { + type: 'header', + size: 5, + text: I18n.getTranslatedObject( + `User "%s" has well known password. We suggest to change it.`, + guiMessage.login, + ), + style: { color: 'orange' }, + sm: 12, + }, + password: { + newLine: true, + label: I18n.getTranslatedObject('New password'), + type: 'password', + help: I18n.getTranslatedObject('Minimal length is 6 chars'), + visible: true, + sm: 12, + md: 6, + }, + passwordRepeat: { + label: I18n.getTranslatedObject('Password repeat'), + type: 'password', + visible: true, + sm: 12, + md: 6, + }, + _send: { + newLine: true, + type: 'sendto', + command: 'admin:setPassword', + jsonData: `{ "oldPassword": "${guiMessage.password}", "login": "${guiMessage.login}", "password": "$\{data.password}", "passwordRepeat": "$\{data.passwordRepeat}" }`, + label: I18n.getTranslatedObject('Set password'), + disabled: + '!data.password || !data.passwordRepeat || data.password.length < 6 || data.password !== data.passwordRepeat', + sm: 6, + md: 3, + variant: 'contained', + }, + }, + }; + } else { + schema = { + type: 'panel', + items: { + _info: { + type: 'staticText', + text: I18n.getTranslatedObject( + 'This message is no more actual and was generated by other instance start', + ), + style: { color: 'grey' }, + sm: 12, + }, + }, + }; + } + + this.sendTo(obj.from, obj.command, { schema }, obj.callback); + } else if (obj.command === 'admin:setPassword') { + // compare password and passwordRepeat + const guiMessage: { login: string; password: string; passwordRepeat: string; oldPassword: string } = + obj.message; + // empty password isn't allowed + if (!guiMessage.password) { + this.sendTo( + obj.from, + obj.command, + { + command: { + command: 'message', + message: I18n.getTranslatedObject("Empty password isn't allowed"), + refresh: true, + }, + }, + obj.callback, + ); + } else if (guiMessage.password !== guiMessage.passwordRepeat) { + this.sendTo( + obj.from, + obj.command, + { + command: { + command: 'message', + message: I18n.getTranslatedObject('Password and password repeat are not equal'), + refresh: true, + }, + }, + obj.callback, + ); + } else if (guiMessage.password.length < 6) { + this.sendTo( + obj.from, + obj.command, + { + command: { + command: 'message', + message: I18n.getTranslatedObject('Password is too short (min 6 chars)'), + refresh: true, + }, + }, + obj.callback, + ); + } else { + void setLinuxPassword(guiMessage.login, guiMessage.oldPassword, guiMessage.password).then(result => { + this.changedPasswords = this.changedPasswords.filter( + item => item.password !== guiMessage.login && item.login !== guiMessage.oldPassword, + ); + this.changedPasswords.push({ + login: guiMessage.login, + password: guiMessage.oldPassword, + result: result === true, + }); + if (result === true) { + this.sendTo( + obj.from, + obj.command, + { + command: { + command: 'message', + message: I18n.getTranslatedObject( + 'Password successfully changed for "%s"', + guiMessage.login, + ), + refresh: true, + }, + }, + obj.callback, + ); + } else { + this.sendTo( + obj.from, + obj.command, + { + command: { + command: 'message', + message: I18n.getTranslatedObject( + `Cannot change password for "%s": %s`, + guiMessage.login, + result, + ), + style: { color: 'red' }, + refresh: true, + }, + }, + obj.callback, + ); + } + }); + } + } + } + /** * Is called when adapter shuts down - callback has to be called under any circumstances! * @@ -849,7 +1066,7 @@ class Admin extends utils.Adapter { endkey: 'system.adapter.\u9999', }); - const operatingSystem = os.platform(); + const operatingSystem = platform(); const instances = await this.getObjectViewAsync('system', 'instance', { startkey: 'system.adapter.\u0000', @@ -1004,16 +1221,24 @@ class Admin extends utils.Adapter { /** * Get the objects db type */ - async getObjectsDbType(): Promise { + async getObjectsDbType(): Promise<'jsonl' | 'file' | 'redis'> { + const hostAlive = await this.getForeignStateAsync(`system.host.${this.host}.alive`); + if (!hostAlive?.val) { + return 'jsonl'; + } const diagData = await this.sendToHostAsync(this.host, 'getDiagData', 'normal'); // @ts-expect-error messages are special and cannot be typed easily - return diagData.objectsType; + return diagData.objectsType as 'jsonl' | 'file' | 'redis'; } /** * Get current npm version from controller */ async getNpmVersion(): Promise { + const hostAlive = await this.getForeignStateAsync(`system.host.${this.host}.alive`); + if (!hostAlive?.val) { + throw new Error('Host is offline'); + } const hostInfo = await this.sendToHostAsync(this.host, 'getHostInfo', {}); // @ts-expect-error messages are special and cannot be typed easily return hostInfo.NPM; @@ -1339,12 +1564,21 @@ class Admin extends utils.Adapter { '', )} was disabled because blocked. Please update ${_adapter} to newer or available version`, ); - this.sendToHost(obj.common.host, 'addNotification', { - scope: 'system', - category: 'accessErrors', // change to 'blocked' when js-controller 4.1. released - instance: obj._id, - message: `Instance version was blocked. Please check for updates and update before restarting the instance`, - }); + const hostAlive = await this.getForeignStateAsync( + `system.host.${obj.common.host}.alive`, + ); + if (hostAlive?.val) { + this.sendToHost(obj.common.host, 'addNotification', { + scope: 'system', + category: 'accessErrors', // change to 'blocked' when js-controller 4.1. released + instance: obj._id, + message: `Instance version was blocked. Please check for updates and update before restarting the instance`, + }); + } else { + this.log.warn( + `Cannot add notification to ${obj.common.host} as it is offline`, + ); + } } } } @@ -1372,9 +1606,9 @@ class Admin extends utils.Adapter { // update icons by all known default objects. Remove this function after 2 years (BF: 2021.04.20) updateIcons(): void { - if (fs.existsSync(`${utils.controllerDir}/io-package.json`)) { + if (existsSync(`${controllerDir}/io-package.json`)) { const ioPackage = JSON.parse( - fs.readFileSync(path.join(utils.controllerDir, 'io-package.json'), { + readFileSync(join(controllerDir, 'io-package.json'), { encoding: 'utf-8', }), ); @@ -1414,31 +1648,35 @@ class Admin extends utils.Adapter { } } - getRecommendedVersions(): Promise<{ node: number; npm: number }> { - return new Promise(resolve => - this.sendToHost(this.host, 'getRepository', {}, repository => { - const repoInfo: { - repoTime: string; - recommendedVersions: { - nodeJsRecommended: number; - npmRecommended: number; - }; - // @ts-expect-error fix later - } = (repository as unknown)?._repoInfo; - - if (repoInfo?.recommendedVersions) { - resolve({ - node: repoInfo.recommendedVersions?.nodeJsRecommended, - npm: repoInfo.recommendedVersions?.npmRecommended, - }); - } else { - resolve({ - node: CURRENT_MAX_MAJOR_NODEJS, - npm: CURRENT_MAX_MAJOR_NPM, - }); - } - }), - ); + async getRecommendedVersions(): Promise<{ node: number; npm: number }> { + // Check if the host running + const hostAlive = await this.getForeignStateAsync(`system.host.${this.host}.alive`); + if (!hostAlive?.val) { + return { + node: CURRENT_MAX_MAJOR_NODEJS, + npm: CURRENT_MAX_MAJOR_NPM, + }; + } + const repository = await this.sendToHostAsync(this.host, 'getRepository', {}); + const repoInfo: { + repoTime: string; + recommendedVersions: { + nodeJsRecommended: number; + npmRecommended: number; + }; + // @ts-expect-error fix later + } = (repository as unknown)?._repoInfo; + + if (repoInfo?.recommendedVersions) { + return { + node: repoInfo.recommendedVersions?.nodeJsRecommended, + npm: repoInfo.recommendedVersions?.npmRecommended, + }; + } + return { + node: CURRENT_MAX_MAJOR_NODEJS, + npm: CURRENT_MAX_MAJOR_NPM, + }; } /** @@ -1486,7 +1724,7 @@ class Admin extends utils.Adapter { this.log.info('Request actual repository...'); // first check if the host is running const aliveState = await this.getForeignStateAsync(`system.host.${this.host}.alive`); - if (!aliveState || !aliveState.val) { + if (!aliveState?.val) { this.log.error('Host is not alive'); // start the next cycle this.restartRepoUpdate(); @@ -1548,8 +1786,8 @@ class Admin extends utils.Adapter { try { const dir = require.resolve('iobroker.js-controller/io-package.json').replace(/\\/g, '/'); // dir is something like ./node_modules/iobroker.js-controller/build/cjs/main.js - if (fs.existsSync(dir)) { - const data = JSON.parse(fs.readFileSync(dir).toString()); + if (existsSync(dir)) { + const data = JSON.parse(readFileSync(dir).toString()); if (data.objects) { objects = data.objects; } @@ -1655,7 +1893,7 @@ class Admin extends utils.Adapter { // check info.connected void this.getObjectAsync('info.connected').then(obj => { if (!obj) { - const packageJson = JSON.parse(fs.readFileSync(`${__dirname}/../io-package.json`).toString('utf8')); + const packageJson = JSON.parse(readFileSync(`${__dirname}/../io-package.json`).toString('utf8')); const obj = packageJson.instanceObjects.find((o: ioBroker.AnyObject) => o._id === 'info.connected'); if (obj) { return this.setObjectAsync(obj._id, obj); @@ -1670,6 +1908,7 @@ class Admin extends utils.Adapter { void this.updateNews().catch(e => this.log.error(`Cannot update news: ${e}`)); this.updateIcons(); void this.validateUserData0().catch(e => this.log.error(`Cannot validate 0_userdata: ${e}`)); + void this.checkWellKnownPasswords().catch(e => this.log.error(`Cannot check well known passwords: ${e}`)); } /** @@ -1684,7 +1923,7 @@ class Admin extends utils.Adapter { } if (!obj) { try { - const ioContent = fs.readFileSync(`${utils.controllerDir}/io-package.json`).toString('utf8'); + const ioContent = readFileSync(`${controllerDir}/io-package.json`).toString('utf8'); const io = JSON.parse(ioContent); if (io.objects) { const userData: ioBroker.MetaObject | null = io.objects.find( @@ -1696,15 +1935,41 @@ class Admin extends utils.Adapter { } } } catch (e) { - this.log.error(`Cannot read ${utils.controllerDir}/io-package.json: ${e}`); + this.log.error(`Cannot read ${controllerDir}/io-package.json: ${e}`); } } } + + async checkWellKnownPasswords(): Promise { + if (process.platform !== 'linux') { + return; + } + const found = await checkWellKnownPasswords(); + if (found) { + this.changedPasswords = this.changedPasswords.filter( + item => item.login !== found.login && item.password !== found.password, + ); + this.changedPasswords.push(found); + + // @ts-expect-error types defined in js-controller 7 + await this.registerNotification('admin', 'wellKnownPassword', I18n.translate('User: %s', found.login), { + contextData: { + admin: { + notification: { + login: found.login, + password: found.password, + offlineMessage: I18n.getTranslatedObject('Offline message', found.login), + }, + }, + }, + }); + } + } } if (require.main !== module) { // Export the constructor in compact mode - module.exports = (options: Partial | undefined) => new Admin(options); + module.exports = (options: Partial | undefined) => new Admin(options); } else { // otherwise start the instance directly (() => new Admin())(); diff --git a/packages/admin/tasks.js b/packages/admin/tasks.js index 0c969ddf0..b5f783af6 100644 --- a/packages/admin/tasks.js +++ b/packages/admin/tasks.js @@ -1,31 +1,96 @@ -const fs = require('node:fs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports +const { statSync, existsSync, writeFileSync, readFileSync } = require('node:fs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports const less = require('less'); -const path = require('node:path'); -const { deleteFoldersRecursive, buildReact, patchHtmlFile, npmInstall, copyFiles } = require('@iobroker/build-tools'); +// eslint-disable-next-line @typescript-eslint/no-require-imports +const { join } = require('node:path'); +// eslint-disable-next-line @typescript-eslint/no-require-imports +const { execFile } = require('node:child_process'); +const { + deleteFoldersRecursive, + /* buildReact, */ patchHtmlFile, + npmInstall, + copyFiles, + // eslint-disable-next-line @typescript-eslint/no-require-imports +} = require('@iobroker/build-tools'); const srcRx = 'src-admin/'; const src = `${__dirname}/${srcRx}`; -const rootFolder = path.join(__dirname, '..', '..'); +const rootFolder = join(__dirname, '..', '..'); const dest = 'adminWww/'; -function build() { - fs.writeFileSync( +function buildCraco() { + return new Promise((resolve, reject) => { + const options = { + stdio: 'pipe', + cwd: src, + }; + + console.log(options.cwd); + + let script = `${rootFolder}/node_modules/@craco/craco/dist/bin/craco.js`; + if (!existsSync(script)) { + script = `${rootFolder}/node_modules/@craco/craco/dist/bin/craco.js`; + } + + if (!existsSync(script)) { + console.error(`Cannot find execution file: ${script}`); + reject(`Cannot find execution file: ${script}`); + } else { + const cmd = 'node'; + const args = [script, '--max-old-space-size=7000', 'build']; + const child = execFile(cmd, args, { cwd: src }); + + child.stderr.pipe(process.stderr); + child.stdout.pipe(process.stdout); + + child.on('exit', (code /* , signal */) => { + // code 1 is a strange error that cannot be explained. Everything is installed but error :( + if (code && code !== 1) { + reject(`Cannot install: ${code}`); + } else { + console.log(`"${cmd} in ${src} finished.`); + // command succeeded + resolve(); + } + }); + } + }); +} + +async function build() { + writeFileSync( `${src}public/lib/js/sparkline.js`, - fs.readFileSync(`${rootFolder}/node_modules/@fnando/sparkline/dist/sparkline.js`), + readFileSync(`${rootFolder}/node_modules/@fnando/sparkline/dist/sparkline.js`), ); - fs.writeFileSync( + writeFileSync( `${src}public/lib/js/sparkline.js.map`, - fs.readFileSync(`${rootFolder}/node_modules/@fnando/sparkline/dist/sparkline.js.map`), + readFileSync(`${rootFolder}/node_modules/@fnando/sparkline/dist/sparkline.js.map`), ); const ace = `${rootFolder}/node_modules/ace-builds/src-min-noconflict/`; - fs.writeFileSync(`${__dirname}/${srcRx}public/lib/js/ace/worker-json.js`, fs.readFileSync(`${ace}worker-json.js`)); - fs.writeFileSync( - `${__dirname}/${srcRx}public/lib/js/ace/ext-searchbox.js`, - fs.readFileSync(`${ace}ext-searchbox.js`), - ); + writeFileSync(`${__dirname}/${srcRx}public/lib/js/ace/worker-json.js`, readFileSync(`${ace}worker-json.js`)); + writeFileSync(`${__dirname}/${srcRx}public/lib/js/ace/ext-searchbox.js`, readFileSync(`${ace}ext-searchbox.js`)); - return buildReact(src, { rootDir: __dirname, ramSize: 7000, craco: true }); + await buildCraco(); + // await buildReact(src, { rootDir: __dirname, ramSize: 7000, craco: true }); + if (existsSync(`${__dirname}/adminWww/index.html`)) { + throw new Error('Front-end was not build to end!'); + } +} + +function syncUtils() { + const stat1 = statSync(`${__dirname}/src-admin/src/helpers/utils.ts`); + const stat2 = statSync(`${__dirname}/src/lib/utils.ts`); + const data1 = readFileSync(`${__dirname}/src-admin/src/helpers/utils.ts`).toString(); + const data2 = readFileSync(`${__dirname}/src/lib/utils.ts`).toString(); + if (data1 !== data2) { + if (stat1.mtimeMs > stat2.mtimeMs) { + writeFileSync(`${__dirname}/src/lib/utils.ts`, data1); + } else { + writeFileSync(`${__dirname}/src-admin/src/helpers/utils.ts`, data2); + } + } } function copyAllFiles() { @@ -34,10 +99,11 @@ function copyAllFiles() { deleteFoldersRecursive(`${__dirname}/${srcRx}public/lib/js/crypto-js`); deleteFoldersRecursive(`${__dirname}/../dm-gui-components/build/src`); deleteFoldersRecursive(`${__dirname}/../jsonConfig/build/src`); + syncUtils(); - let readme = fs.readFileSync(`${__dirname}/../../README.md`).toString('utf8'); + let readme = readFileSync(`${__dirname}/../../README.md`).toString('utf8'); readme = readme.replaceAll('packages/admin/', ''); - fs.writeFileSync(`${__dirname}/README.md`, readme); + writeFileSync(`${__dirname}/README.md`, readme); copyFiles([`${srcRx}build/*`, `!${srcRx}build/index.html`, `!${srcRx}build/static/js/*.js`], dest); @@ -71,18 +137,18 @@ function copyAllFiles() { } async function configCSS() { - const selectID = await less.render(fs.readFileSync(`./${srcRx}less/selectID.less`).toString('utf8'), { + const selectID = await less.render(readFileSync(`./${srcRx}less/selectID.less`).toString('utf8'), { filename: 'selectID.less', compress: true, paths: [`./${srcRx}less`], }); - const adapterLess = await less.render(fs.readFileSync(`./${srcRx}less/adapter.less`).toString('utf8'), { + const adapterLess = await less.render(readFileSync(`./${srcRx}less/adapter.less`).toString('utf8'), { filename: 'adapter.less', compress: true, paths: [`./${srcRx}less`], }); const materializeCorrect = await less.render( - fs.readFileSync(`./${srcRx}less/materializeCorrect.less`).toString('utf8'), + readFileSync(`./${srcRx}less/materializeCorrect.less`).toString('utf8'), { filename: 'materializeCorrect.less', compress: true, @@ -90,29 +156,26 @@ async function configCSS() { }, ); - fs.writeFileSync(`./${srcRx}public/css/adapter.css`, selectID.css + adapterLess.css + materializeCorrect.css); + writeFileSync(`./${srcRx}public/css/adapter.css`, selectID.css + adapterLess.css + materializeCorrect.css); } async function iobCSS() { - const selectID = await less.render(fs.readFileSync(`./${srcRx}less/selectID.less`).toString('utf8'), { + const selectID = await less.render(readFileSync(`./${srcRx}less/selectID.less`).toString('utf8'), { filename: 'selectID.less', compress: true, paths: [`./${srcRx}less`], }); - fs.writeFileSync(`./${srcRx}public/lib/css/iob/selectID.css`, selectID.css); + writeFileSync(`./${srcRx}public/lib/css/iob/selectID.css`, selectID.css); } async function treeTableCSS() { - const treeTable = await less.render( - fs.readFileSync(`./${srcRx}less/jquery.treetable.theme.less`).toString('utf8'), - { - filename: 'selectID.less', - compress: true, - paths: [`./${srcRx}less`], - }, - ); - fs.writeFileSync(`./${srcRx}public/lib/css/jquery.treetable.theme.css`, treeTable.css); + const treeTable = await less.render(readFileSync(`./${srcRx}less/jquery.treetable.theme.less`).toString('utf8'), { + filename: 'selectID.less', + compress: true, + paths: [`./${srcRx}less`], + }); + writeFileSync(`./${srcRx}public/lib/css/jquery.treetable.theme.css`, treeTable.css); } function clean() { @@ -120,7 +183,11 @@ function clean() { deleteFoldersRecursive(`${__dirname}/${srcRx}/build`); } -if (process.argv.find(e => e.replace(/^-*/, '') === 'react-0-configCSS')) { +if (process.argv.includes('--backend-i18n')) { + copyFiles(['src/i18n/*'], 'build-backend/i18n'); + syncUtils(); +} else if (process.argv.find(e => e.replace(/^-*/, '') === 'react-0-configCSS')) { + syncUtils(); configCSS().catch(e => { console.error(e); process.exit(1); @@ -136,9 +203,10 @@ if (process.argv.find(e => e.replace(/^-*/, '') === 'react-0-configCSS')) { process.exit(1); }); } else if (process.argv.find(e => e.replace(/^-*/, '') === 'react-1-clean')) { + syncUtils(); clean(); } else if (process.argv.find(e => e.replace(/^-*/, '') === 'react-2-npm')) { - if (!fs.existsSync(`${src}node_modules`)) { + if (!existsSync(`${src}node_modules`)) { npmInstall(src).catch(e => { console.error(e); process.exit(1); @@ -157,10 +225,11 @@ if (process.argv.find(e => e.replace(/^-*/, '') === 'react-0-configCSS')) { process.exit(1); }); } else { + syncUtils(); configCSS() .then(async () => { clean(); - if (!fs.existsSync(`${src}node_modules`)) { + if (!existsSync(`${src}node_modules`)) { await npmInstall(src); } await configCSS(); diff --git a/packages/admin/test/testReplaceLink.js b/packages/admin/test/testReplaceLink.js new file mode 100644 index 000000000..2a9f07a01 --- /dev/null +++ b/packages/admin/test/testReplaceLink.js @@ -0,0 +1,7674 @@ +const expect = require('chai').expect; + +const { replaceLink } = require('../build-backend/lib/utils'); + +const instances = { + 'system.adapter.admin.0': { + _id: 'system.adapter.admin.0', + type: 'instance', + common: { + name: 'admin', + version: '7.1.5', + titleLang: { + en: 'Admin', + de: 'Admin', + ru: 'Админ', + pt: 'Admin', + pl: 'Admin', + fr: 'Admin', + nl: 'Admin', + it: 'Admin', + es: 'Admin', + 'zh-cn': 'Admin', + uk: 'Admin', + }, + title: 'Admin', + connectionType: 'local', + dataSource: 'push', + desc: { + en: 'The configuration of ioBroker via Web-Interface', + de: 'Die Konfiguration von ioBroker über das Web-Interface', + ru: 'Конфигурация ioBroker через веб-интерфейс', + pt: 'A configuração do ioBroker via Web-Interface', + fr: 'La configuration de ioBroker via Web-Interface', + nl: 'De configuratie van ioBroker via de webinterface', + it: 'La configurazione di ioBroker tramite interfaccia Web', + 'zh-cn': '配置ioBroker的Web界面', + es: 'La configuración de ioBroker a través de la interfaz web', + pl: 'Konfiguracja ioBroker za pomocą interfejsu WWW', + uk: 'Конфігурація ioBroker через веб-інтерфейс', + }, + docs: { + en: 'docs/en/admin.md', + ru: 'docs/ru/admin.md', + de: [ + 'docs/de/admin.md', + 'docs/de/admin/tab-adapters.md', + 'docs/de/admin/tab-instances.md', + 'docs/de/admin/tab-objects.md', + 'docs/de/admin/tab-states.md', + 'docs/de/admin/tab-groups.md', + 'docs/de/admin/tab-users.md', + 'docs/de/admin/tab-events.md', + 'docs/de/admin/tab-hosts.md', + 'docs/de/admin/tab-enums.md', + 'docs/de/admin/tab-log.md', + 'docs/de/admin/tab-system.md', + ], + pt: 'docs/pt/admin.md', + nl: 'docs/nl/admin.md', + es: 'docs/es/admin.md', + fr: 'docs/fr/admin.md', + it: 'docs/it/admin.md', + pl: 'docs/pl/admin.md', + 'zh-cn': 'docs/zh-cn/admin.md', + }, + materialize: true, + mode: 'daemon', + platform: 'Javascript/Node.js', + loglevel: 'info', + icon: 'admin.svg', + messagebox: true, + enabled: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.admin/master/packages/admin/admin/admin.svg', + keywords: [ + 'setup', + 'config', + 'update', + 'upgrade', + 'system', + 'konfiguration', + 'administration', + 'einrichtung', + 'wartung', + ], + compact: true, + readme: 'https://github.com/ioBroker/ioBroker.admin/blob/master/README.md', + authors: ['bluefox ', 'hobbyquaker '], + dependencies: [ + { + 'js-controller': '>=3.3.22', + }, + ], + type: 'general', + license: 'MIT', + logTransporter: true, + stopBeforeUpdate: true, + wwwDontUpload: true, + eraseOnUpload: true, + nogit: true, + welcomeScreenPro: [ + { + link: 'admin/index.html', + name: 'Admin', + img: 'admin/img/admin.svg', + color: 'pink', + order: 5, + localLinks: '_default', + localLink: true, + }, + ], + localLinks: { + _default: { + link: '%protocol%://%bind%:%port%', + pro: 'admin/index.html', + name: { + en: 'Admin', + ru: 'Админ', + }, + icon: 'admin/img/admin.svg', + color: 'pink', + order: 5, + intro: true, + }, + }, + plugins: { + sentry: { + dsn: 'https://9d2aaf29332a4999b133c693f43203b9@sentry.iobroker.net/18', + }, + }, + jsonConfig: true, + adminUI: { + config: 'json', + }, + installedVersion: '7.1.5', + host: 'NanoPi-R5S', + installedFrom: 'iobroker.admin@latest', + licenseInformation: { + license: 'MIT', + type: 'free', + }, + tier: 1, + }, + native: { + port: 8081, + auth: false, + secure: false, + bind: '0.0.0.0', + cache: false, + autoUpdate: 24, + accessLimit: false, + accessApplyRights: false, + accessAllowedConfigs: [], + accessAllowedTabs: [], + certPublic: '', + certPrivate: '', + certChained: '', + ttl: 3600, + defaultUser: 'admin', + tmpPath: '/tmp', + tmpPathAllow: false, + thresholdValue: 200, + leEnabled: false, + leUpdate: false, + leCheckPort: 80, + loginBackgroundColor: '', + loginBackgroundImage: false, + loginHideLogo: false, + loginMotto: '', + language: '', + reverseProxy: [], + loadingBackgroundColor: '', + loadingHideLogo: false, + loadingBackgroundImage: false, + leCollection: false, + doNotCheckPublicIP: false, + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1727349053727, + protectedNative: [], + encryptedNative: [], + notifications: [ + { + scope: 'admin', + name: { + en: 'Administration', + de: 'Administration', + ru: 'Администрация', + pt: 'Administração', + nl: 'Administratie', + fr: 'Administration', + it: 'Amministrazione', + es: 'Administración', + pl: 'Administracja', + uk: 'Адміністрація', + 'zh-cn': '行政部门', + }, + description: { + en: 'These notifications represent news regarding installed adapters or general ioBroker information.', + de: 'Diese Benachrichtigungen enthalten Neuigkeiten zu installierten Adaptern oder allgemeine ioBroker-Informationen.', + ru: 'Эти уведомления представляют новости о установленных адаптерах или общей информации ioBroker.', + pt: 'Estas notificações representam notícias sobre adaptadores instalados ou informações gerais do ioBroker.', + nl: 'Deze berichten zijn nieuws over geïnstalleerde adapters of algemene ioBroker informatie.', + fr: 'Ces notifications représentent des nouvelles concernant les adaptateurs installés ou les informations générales ioBroker.', + it: 'Queste notifiche rappresentano notizie riguardanti adattatori installati o informazioni generali su ioBroker.', + es: 'Estas notificaciones representan noticias sobre adaptadores instalados o información general ioBroker.', + pl: 'Noty te reprezentują informacje dotyczące zainstalowanych adapterów lub ogólnie dostępnych informacji ioBrokera.', + uk: 'Ці повідомлення представляють новини про встановлені адаптери або загальні відомості про ioBroker.', + 'zh-cn': '这些通知是有关安装的适应器或一般的气箱信息的新闻。.', + }, + categories: [ + { + category: 'adapterUpdates', + name: { + en: 'Adapter updates', + de: 'Adapter-Updates', + ru: 'Обновления адаптера', + pt: 'Actualizações do adaptador', + nl: 'Adapter updates', + fr: "Mises à jour de l'adaptateur", + it: "Aggiornamenti dell'adattatore", + es: 'Actualizaciones de adaptadores', + pl: 'Aktualizacje adapterów', + uk: 'Оновлення адаптерів', + 'zh-cn': '适配器更新', + }, + severity: 'notify', + description: { + en: 'New adapter updates are available for your ioBroker.', + de: 'Es sind neue Adapter Updates für deinen ioBroker verfügbar.', + ru: 'Для вашего ioBroker доступны новые обновления адаптера.', + pt: 'Estão disponíveis novas actualizações de adaptadores para o seu ioBroker.', + nl: 'Nieuwe adapterupdates zijn beschikbaar voor uw ioBroker.', + fr: "De nouvelles mises à jour de l'adaptateur sont disponibles pour ton ioBroker.", + it: "Sono disponibili nuovi aggiornamenti dell'adattatore per il vostro ioBroker.", + es: 'Hay nuevas actualizaciones de adaptadores disponibles para su ioBroker.', + pl: 'Dostępne są nowe aktualizacje adaptera dla ioBroker.', + uk: 'Для вашого ioBroker доступні нові оновлення адаптерів.', + 'zh-cn': '您的 ioBroker 可以使用新的适配器更新。', + }, + regex: [], + limit: 1, + }, + { + category: 'infoNews', + name: { + en: 'General news', + de: 'Allgemeine Nachrichten', + ru: 'Общие новости', + pt: 'Notícia geral', + nl: 'Generaal', + fr: 'Nouvelles générales', + it: 'Notizie generali', + es: 'Noticias generales', + pl: 'Strona oficjalna', + uk: 'Новини', + 'zh-cn': '新闻', + }, + severity: 'notify', + description: { + en: 'These messages represent general news, which just have informal purpose and do not need to be read immediately.', + de: 'Diese Nachrichten stellen allgemeine Nachrichten dar, die nur informellen Zweck haben und nicht sofort gelesen werden müssen.', + ru: 'Эти сообщения представляют собой общие новости, которые просто имеют неформальную цель и не нужно читать немедленно.', + pt: 'Essas mensagens representam notícias gerais, que apenas têm um propósito informal e não precisam ser lidas imediatamente.', + nl: 'Deze berichten vertegenwoordigen algemene nieuws, wat informeel doel heeft en niet onmiddellijk hoeft te worden gelezen.', + fr: 'Ces messages représentent des nouvelles générales, qui ont juste un but informel et ne doivent pas être lus immédiatement.', + it: 'Questi messaggi rappresentano notizie generali, che hanno solo scopo informale e non devono essere letti immediatamente.', + es: 'Estos mensajes representan noticias generales, que sólo tienen un propósito informal y no necesitan ser leídos inmediatamente.', + pl: 'Wiadomości te reprezentują ogólnokrajowe wiadomości, które tylko mają nieformalny cel i nie muszą być odczytane natychmiast.', + uk: 'Ці повідомлення представляють загальні новини, які просто мають неформальне призначення і не потрібно негайно прочитати.', + 'zh-cn': '这些信息是一般新闻,这只是非正式目的,不需要立即阅读。.', + }, + regex: [], + limit: 10, + }, + { + category: 'warningNews', + name: { + en: 'Important news', + de: 'Wichtige Nachrichten', + ru: 'Важные новости', + pt: 'Notícia importante', + nl: 'Belangrijk nieuws', + fr: 'Nouvelles importantes', + it: 'Notizie importanti', + es: 'Noticias importantes', + pl: 'Important news', + uk: 'Новини', + 'zh-cn': '重要的新闻', + }, + severity: 'info', + description: { + en: 'These messages represent adapter warnings and important changes in the near future.', + de: 'Diese Nachrichten stellen Adapterwarnungen und wichtige Veränderungen in der nahen Zukunft dar.', + ru: 'Эти сообщения представляют предупреждение о адаптере и важные изменения в ближайшем будущем.', + pt: 'Estas mensagens representam avisos de adaptadores e mudanças importantes no futuro próximo.', + nl: 'Deze berichten vertegenwoordigen adapter waarschuwingen en belangrijke veranderingen in de nabije toekomst.', + fr: "Ces messages représentent des avertissements d'adaptateur et des changements importants dans un proche avenir.", + it: 'Questi messaggi rappresentano avvisi di adattatore e cambiamenti importanti nel prossimo futuro.', + es: 'Estos mensajes representan advertencias de adaptador y cambios importantes en el futuro cercano.', + pl: 'Wiadomości te reprezentują ostrzeżenia adaptatora i ważne zmiany w najbliższej przyszłości.', + uk: 'Ці повідомлення представляють попередження та важливі зміни в найближчому майбутньому.', + 'zh-cn': '这些信息是适应的预警和近期的重要变化。.', + }, + regex: [], + limit: 10, + }, + { + category: 'dangerNews', + name: { + en: 'Very important news', + de: 'Sehr wichtige Nachrichten', + ru: 'Очень важные новости', + pt: 'Notícia muito importante', + nl: 'Heel belangrijk', + fr: 'Nouvelles très importantes', + it: 'Notizie molto importanti', + es: 'Noticias muy importantes', + pl: 'Ważne wiadomości', + uk: 'Останні новини', + 'zh-cn': '非常重要的新闻', + }, + severity: 'alert', + description: { + en: 'These notifications are very important. They may give you a hint that an adapter upgrade is required right now to maintain functionality.', + de: 'Diese Benachrichtigungen sind sehr wichtig. Sie können Ihnen einen Hinweis geben, dass ein Adapter-Upgrade jetzt erforderlich ist, um die Funktionalität zu erhalten.', + ru: 'Эти уведомления очень важны. Они могут дать вам подсказку, что обновление адаптера требуется прямо сейчас для поддержания функциональности.', + pt: 'Estas notificações são muito importantes. Eles podem lhe dar uma dica de que uma atualização do adaptador é necessária agora para manter a funcionalidade.', + nl: 'Deze berichten zijn heel belangrijk. Ze kunnen je een hint geven dat een adapter upgrade nu nodig is om functionaliteit te behouden.', + fr: "Ces notifications sont très importantes. Ils peuvent vous donner un indice qu'une mise à niveau d'adaptateur est nécessaire pour maintenir la fonctionnalité.", + it: 'Queste notifiche sono molto importanti. Essi possono dare un suggerimento che un aggiornamento adattatore è necessario in questo momento per mantenere la funzionalità.', + es: 'Estas notificaciones son muy importantes. Pueden darle una pista de que se requiere una actualización del adaptador ahora mismo para mantener la funcionalidad.', + pl: 'Te informacje są bardzo ważne. Mogą dać wskazówki, że ulepszanie adapteru jest niezbędne do utrzymania funkcji.', + uk: 'Ці повідомлення дуже важливі. Вони можуть надати вам підказку, що оновлення адаптера потрібно прямо зараз для підтримки функціональності.', + 'zh-cn': '这些通知非常重要。 他们可以向你说明,适应人员升级现在需要保持功能。.', + }, + regex: [], + limit: 10, + }, + ], + }, + ], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: { + en: 'Information', + de: 'Information', + ru: 'Информация', + pt: 'Em formação', + nl: 'Informatie', + fr: 'Information', + it: 'Informazione', + es: 'Información', + pl: 'Informacja', + 'zh-cn': '信息', + }, + }, + native: {}, + }, + { + _id: '', + type: 'meta', + common: { + name: { + en: 'user files and images for background', + de: 'Benutzerdateien und Bilder für den Hintergrund', + ru: 'пользовательские файлы и изображения для фона', + pt: 'arquivos e imagens do usuário para plano de fundo', + nl: 'gebruikersbestanden en afbeeldingen voor achtergrond', + fr: "fichiers utilisateur et images pour l'arrière-plan", + it: 'file utente e immagini per lo sfondo', + es: 'archivos de usuario e imágenes para el fondo', + pl: 'pliki użytkownika i obrazy w tle', + 'zh-cn': '背景的用户文件和图像', + }, + type: 'meta.user', + }, + native: {}, + }, + { + _id: 'info.connected', + type: 'state', + common: { + role: 'state', + name: { + en: 'Info about connected socket clients', + de: 'Informationen über verbundene Socket-Clients', + ru: 'Информация о подключенных клиентах сокетов', + pt: 'Informações sobre clientes de soquete conectados', + nl: 'Info over aangesloten socket-clients', + fr: 'Informations sur les clients socket connectés', + it: 'Informazioni sui client socket connessi', + es: 'Información sobre clientes de socket conectados', + pl: 'Informacje o podłączonych klientach gniazd', + 'zh-cn': '有关已连接套接字客户端的信息', + }, + type: 'string', + read: true, + write: false, + def: '', + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + role: 'indicator.connected', + name: { + en: 'HTTP server started', + de: 'HTTP-Server gestartet', + ru: 'HTTP-сервер запущен', + pt: 'Servidor HTTP iniciado', + nl: 'HTTP-server gestart', + fr: 'Serveur HTTP démarré', + it: 'Server HTTP avviato', + es: 'Servidor HTTP iniciado', + pl: 'Uruchomiono serwer HTTP', + 'zh-cn': 'HTTP 服务器已启动', + }, + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.newsFeed', + type: 'state', + common: { + name: { + en: 'Last news feed as JSON', + de: 'Letzter Newsfeed als JSON', + ru: 'Лента последних новостей в формате JSON', + pt: 'Último feed de notícias como JSON', + nl: 'Laatste nieuwsfeed als JSON', + fr: "Dernier fil d'actualité au format JSON", + it: 'Ultimo feed di notizie come JSON', + es: 'Últimas noticias como JSON', + pl: 'Ostatni kanał wiadomości jako JSON', + 'zh-cn': '最后一个新闻提要为 JSON', + }, + type: 'json', + read: true, + write: false, + }, + }, + { + _id: 'info.newsETag', + type: 'state', + common: { + name: { + en: 'Etag for news feed', + de: 'Etag für Newsfeed', + ru: 'Etag для новостной ленты', + pt: 'Etag para feed de notícias', + nl: 'Etag voor nieuwsfeed', + fr: "Etag pour le fil d'actualité", + it: 'Etag per il feed di notizie', + es: 'Etag para noticias', + pl: 'Etag dla kanału informacyjnego', + 'zh-cn': '用于新闻提要的 Etag', + }, + type: 'string', + read: true, + write: false, + }, + }, + { + _id: 'info.newsLastId', + type: 'state', + common: { + name: { + en: 'Last news ID', + de: 'Letzte Nachrichten-ID', + ru: 'Идентификатор последней новости', + pt: 'ID da última notícia', + nl: 'Laatste nieuws-ID', + fr: 'Identifiant des dernières nouvelles', + it: 'Ultime notizie ID', + es: 'ID de última noticia', + pl: 'Identyfikator ostatnich wiadomości', + 'zh-cn': '最新消息 ID', + }, + type: 'string', + read: true, + write: false, + }, + }, + { + _id: 'info.updatesList', + type: 'state', + common: { + role: 'indicator.updates', + name: { + en: 'List of adapters to update', + de: 'Liste der zu aktualisierenden Adapter', + ru: 'Список адаптеров для обновления', + pt: 'Lista de adaptadores para atualizar', + nl: 'Lijst met adapters die moeten worden bijgewerkt', + fr: 'Liste des adaptateurs à mettre à jour', + it: 'Elenco degli adattatori da aggiornare', + es: 'Lista de adaptadores para actualizar', + pl: 'Lista adapterów do aktualizacji', + 'zh-cn': '要更新的适配器列表', + }, + type: 'string', + read: true, + write: false, + def: '', + }, + native: {}, + }, + ], + objects: [], + acl: { + object: 1636, + state: 1636, + file: 1632, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + }, + 'system.adapter.discovery.0': { + _id: 'system.adapter.discovery.0', + type: 'instance', + common: { + name: 'discovery', + version: '5.0.0', + title: 'Discovery devices', + titleLang: { + en: 'Discovery devices', + de: 'Gerätesuche', + ru: 'Драйвер поиска устройств', + pt: 'Dispositivos de descoberta', + nl: 'Ontdekkingsapparaten', + fr: 'Dispositifs de découverte', + it: 'Dispositivi di scoperta', + es: 'Dispositivos de descubrimiento', + pl: 'Urządzenia Discovery', + 'zh-cn': '发现设备', + }, + desc: { + en: 'This adapter tries to discover all known devices in your network and on your machine', + de: 'Dieser Adapter versucht, alle bekannten Geräte in Ihrem Netzwerk und auf Ihrem Computer zu finden', + ru: 'Этот адаптер пытается обнаружить все известные устройства в вашей сети и на вашем компьютере', + pt: 'Este adaptador tenta descobrir todos os dispositivos conhecidos da sua rede e da sua máquina', + nl: 'Deze adapter probeert alle bekende apparaten in uw netwerk en op uw computer te ontdekken', + fr: 'Cet adaptateur essaie de découvrir tous les périphériques connus sur votre réseau et sur votre machine', + it: 'Questo adattatore tenta di rilevare tutti i dispositivi noti nella rete e sulla macchina', + es: 'Este adaptador intenta descubrir todos los dispositivos conocidos en su red y en su máquina', + pl: 'Ten adapter próbuje wykryć wszystkie znane urządzenia w sieci i na twoim komputerze', + 'zh-cn': '这个适配器将尝试发现在您局域网和主机上的所有已知设备', + }, + authors: ['bluefox '], + license: 'MIT', + platform: 'Javascript/Node.js', + mode: 'daemon', + enabled: true, + compact: true, + singletonHost: true, + materialize: true, + messagebox: true, + readme: 'https://github.com/ioBroker/ioBroker.discovery/blob/master/README.md', + dependencies: [ + { + 'js-controller': '>=2.0.0', + }, + ], + loglevel: 'info', + icon: 'discovery.png', + keywords: ['poll', 'discovery', 'ip'], + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.discovery/master/admin/discovery.png', + type: 'general', + plugins: { + sentry: { + dsn: 'https://464b38d930eb4ee7b3e426620f52d256@sentry.iobroker.net/31', + }, + }, + adminUI: { + config: 'none', + }, + connectionType: 'local', + dataSource: 'none', + tier: 3, + installedVersion: '5.0.0', + host: 'NanoPi-R5S', + installedFrom: 'iobroker.discovery@5.0.0', + licenseInformation: { + license: 'MIT', + type: 'free', + }, + }, + native: { + pingTimeout: 1000, + pingOwnIP: '', + pingOwnNetmask: '', + pingBlock: 20, + onlyLocal: false, + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1721744461510, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: 'devicesProgress', + type: 'state', + common: { + role: 'value', + name: 'Find devices progress', + min: 0, + max: 100, + type: 'number', + unit: '%', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'servicesProgress', + type: 'state', + common: { + role: 'value', + name: 'Find services on devices progress', + min: 0, + max: 100, + type: 'number', + unit: '%', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'instancesFound', + type: 'state', + common: { + role: 'value', + name: 'Found services', + type: 'number', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'devicesFound', + type: 'state', + common: { + role: 'value', + name: 'Found devices', + type: 'number', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'scanRunning', + type: 'state', + common: { + role: 'indicator', + name: 'Is scan now running', + type: 'boolean', + read: true, + write: false, + }, + native: {}, + }, + ], + objects: [], + acl: { + object: 1636, + state: 1636, + file: 1632, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + }, + 'system.adapter.backitup.0': { + _id: 'system.adapter.backitup.0', + type: 'instance', + common: { + name: 'backitup', + version: '3.0.22', + title: 'BackItUp', + titleLang: { + en: 'BackItUp', + de: 'BackItUp', + ru: 'BackItUp - Резервное копирование', + pt: 'BackItUp', + nl: 'BackItUp', + fr: 'BackItUp', + it: 'BackItUp', + es: 'BackItUp', + pl: 'Kopia zapasowa', + uk: 'Посилання', + 'zh-cn': 'BackItUp', + }, + desc: { + en: 'ioBroker.backitup allows you to backup and restore your ioBroker installation and other systems, such as databases, Zigbee, scripts and many more', + de: 'ioBroker.backitup ermöglicht es Ihnen, Ihre ioBroker-Installation und andere Systeme wie Datenbanken, Zigbee, Skripte und vieles mehr zu sichern und wiederherzustellen', + ru: 'ioBroker.backitup позволяет резервировать и восстанавливать установку ioBroker и другие системы, такие как базы данных, Zigbee, скрипты и многое другое', + pt: 'ioBroker.backitup permite fazer backup e restaurar sua instalação ioBroker e outros sistemas, como bancos de dados, Zigbee, scripts e muito mais', + nl: 'ioBroker.backitup kunt u back-up en herstel van uw ioBroker installatie en andere systemen, zoals databases, Zigbee, scripts en nog veel meer', + fr: "ioBroker.backitup vous permet de sauvegarder et de restaurer votre installation ioBroker et d'autres systèmes, tels que les bases de données, Zigbee, scripts et beaucoup plus", + it: "ioBroker.backitup consente di eseguire il backup e ripristinare l'installazione di ioBroker e altri sistemi, come database, Zigbee, script e molti altri", + es: 'ioBroker.backitup le permite respaldar y restaurar su instalación de iBroker y otros sistemas, como bases de datos, Zigbee, scripts y muchos más', + pl: 'ioBroker.backitup pozwala na tworzenie kopii zapasowych i przywracanie instalacji joBroker i innych systemów, takich jak bazy danych, Zigbee, skrypty i wiele innych', + uk: 'ioBroker.backitup дозволяє резервну копіювати та відновити встановлення та інші системи, такі як бази даних, Zigbee, скрипти та багато іншого', + 'zh-cn': '约布罗克。 备份允许您备份并恢复您的 ioBroker 安装和其他系统, 如数据库、 Zigbee、 脚本和更多', + }, + authors: ['simatec ', 'bluefox '], + osDependencies: { + linux: ['cifs-utils', 'nfs-common'], + }, + docs: { + en: 'docs/en/backitup.md', + de: 'docs/de/backitup.md', + }, + platform: 'Javascript/Node.js', + mode: 'daemon', + compact: true, + icon: 'backitup.png', + materialize: true, + messagebox: true, + stopBeforeUpdate: true, + connectionType: 'local', + dataSource: 'assumption', + materializeTab: true, + adminTab: { + name: { + en: 'Backup', + de: 'Backup', + ru: 'Назад', + pt: 'Backup', + nl: 'Versterking', + fr: 'Sauvegarde', + it: 'Backup', + es: 'Copia de seguridad', + pl: 'Backup', + uk: 'Зареєструватися', + 'zh-cn': '包装', + }, + ignoreConfigUpdate: true, + singleton: false, + 'fa-icon': "", + }, + dependencies: [ + { + 'js-controller': '>=5.0.19', + }, + ], + globalDependencies: [ + { + admin: '>=6.17.11', + }, + ], + adminUI: { + config: 'json', + tab: 'materialize', + }, + enabled: true, + extIcon: 'https://raw.githubusercontent.com/simatec/ioBroker.backitup/master/admin/backitup.png', + keywords: [ + 'Backup', + 'iob', + 'Homematic', + 'Grafana', + 'Zigbee', + 'MySql', + 'InfluxDB', + 'Onedrive', + 'GoogleDrive', + 'Dropbox', + 'WebDav', + 'NFS', + 'CIFS', + 'FTP', + 'NAS', + 'Backitup', + 'JavaScript', + 'Restore', + 'Redis', + 'Node-Red', + 'Yahka', + ], + readme: 'https://github.com/simatec/ioBroker.backitup/blob/master/README.md', + loglevel: 'info', + type: 'general', + license: 'MIT', + plugins: { + sentry: { + dsn: 'https://e8510540c3a343aa8ce5678a4b3c8107@sentry.iobroker.net/36', + }, + }, + messages: [ + { + condition: { + operand: 'and', + rules: ['oldVersion<2.9.0', 'newVersion>=2.9.0'], + }, + title: { + en: 'Changes for CIFS under Node 20.x.x', + de: 'Änderungen für CIFS unter Node 20.x.x', + ru: 'Изменения для CIFS под Node 20.x.x', + pt: 'Alterações para CIFS em Node 20.x.x', + nl: 'Veranderingen voor CIFS onder Node 20.x', + fr: 'Changements pour le CIFS sous le no 20.x.x', + it: 'Modifiche per CIFS sotto Node 20.x.x', + es: 'Cambios para CIFS bajo Nodo 20.x.x', + pl: 'Zmiany dla CIFS pod numerem 20.x', + uk: 'Зміни для CIFS під Node 20.x.x', + 'zh-cn': '第20.x号CIFS的变动', + }, + text: { + en: 'FritzNAS users must enable the "Cache Loose" option in the Backitup settings for proper CIFS function under Node 20. Without this option, no backup can be written to the FritzNAS.', + de: 'FritzNAS-Benutzer müssen die Option "Cache Loose" in den Backitup-Einstellungen für die richtige CIFS-Funktion unter Node 20 aktivieren. Ohne diese Option kann kein Backup auf das FritzNAS geschrieben werden.', + ru: 'Пользователи FritzNAS должны включить опцию "Cache Loose" в настройках Backitup для правильной функции CIFS под Node 20. Без этого варианта резервное копирование не может быть написано на FritzNAS.', + pt: 'Os usuários do FritzNAS devem ativar a opção "Cache Loose" nas configurações do Backitup para a função CIFS apropriada sob o Node 20. Sem esta opção, nenhum backup pode ser escrito para o FritzNAS.', + nl: 'FritzNAS gebruikers moeten de "Cache Loose" optie in de Backitup settings voor goede CIFS-functies onder de 20. Zonder deze optie kan er geen back-up geschreven worden aan de FritzNAS.', + fr: 'Les utilisateurs de FritzNAS doivent activer l\'option "Cache Loose" dans les paramètres de sauvegarde de la fonction CIFS appropriée sous le numéro 20. Sans cette option, aucune sauvegarde ne peut être écrite au FritzNAS.', + it: 'Gli utenti di FritzNAS devono abilitare l\'opzione "Cache Loose" nelle impostazioni di Backitup per una corretta funzione CIFS sotto Node 20. Senza questa opzione, nessun backup può essere scritto al FritzNAS.', + es: 'Los usuarios de FritzNAS deben habilitar la opción "Cache Loose" en la configuración de Backitup para la función apropiada de CIFS bajo Nodo 20. Sin esta opción, no se puede escribir copia de seguridad al FritzNAS.', + pl: 'Użytkownicy FritzNAS muszą umożliwić opcję „Cache Loose” w ustawieniach Backitup dla funkcji CIFS. Bez tej opcji nie można pisać FritzNAS.', + uk: 'Користувачі FritzNAS повинні увімкнути параметр "Cache Loose" у налаштуваннях Backitup для коректної функції CIFS під Node 20. Без цього варіанту не можна писати на ФрицНАС.', + 'zh-cn': + 'FritzNAS用户必须能够使Backitup环境中的“Cache Loose”方案能够正常的CIFS功能。 没有这种选择,就不能向弗朗西斯·弗朗索瓦斯写回来。.', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + }, + { + condition: { + operand: 'and', + rules: ['oldVersion<2.10.0', 'newVersion>=2.10.0'], + }, + title: { + en: 'Breaking Changes for Docker mapping ports', + de: 'Wichtige Änderungen für Docker Mapping Ports', + ru: 'Перерыв изменений для картографических портов Docker', + pt: 'Alterações de quebra para portas de mapeamento Docker', + nl: 'Wijzigingen voor Docker-mappingpoorten breken', + fr: 'Briser les changements pour les ports de cartographie Docker', + it: 'Cambiamenti di rottura per porte di mappatura Docker', + es: 'Cambios de ruptura para puertos de mapeo de Docker', + pl: 'Breaking Changes for Docker mapowanie portów', + uk: 'Зміни для портів Docker', + 'zh-cn': 'Docker 映射端口的中断更改', + }, + text: { + en: 'Due to changes, the mapping ports must be adapted for Docker containers. All port details can be found in the documentation.', + de: 'Durch Änderungen müssen die Mapping Ports für Docker Container angepasst werden. Alle Port-Details finden Sie in der Dokumentation.', + ru: 'Из-за изменений порты картографирования должны быть адаптированы для контейнеров Docker. Все детали порта можно найти в документации.', + pt: 'Devido a mudanças, as portas de mapeamento devem ser adaptadas para contentores Docker. Todos os detalhes da porta podem ser encontrados na documentação.', + nl: 'Door veranderingen moeten de ports aangepast worden voor Docker containers. Alle havengegevens zijn te vinden in de documentatie.', + fr: 'En raison de changements, les ports de cartographie doivent être adaptés pour les conteneurs Docker. Tous les détails du port se trouvent dans la documentation.', + it: 'A causa delle modifiche, le porte di mappatura devono essere adattate per contenitori Docker. Tutti i dettagli della porta si trovano nella documentazione.', + es: 'Debido a los cambios, los puertos de mapeo deben ser adaptados para contenedores Docker. Todos los detalles del puerto se pueden encontrar en la documentación.', + pl: 'Ze względu na zmiany, porty mapujące muszą być dostosowane do kontenerów Docker. Wszystkie szczegóły portu znajdują się w dokumentacji.', + uk: "У зв'язку з змінами порти картування повинні бути адаптовані для контейнерів Docker. Усі деталі порту можна знайти в документації.", + 'zh-cn': '由于变化,绘图端口必须适应多克容器. 所有端口细节均可在文档中找到.', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + link: 'https://github.com/simatec/ioBroker.backitup/wiki/ioBroker.backitup-Wiki-English#docker-support', + linkText: { + en: 'Docker-Documentation', + de: 'Docker-Dokumentation', + ru: 'Docker-Document', + pt: 'Docker-Documentação', + nl: 'Dockerdocumentatie', + fr: 'Docker-Documentation', + it: 'Docker-Documentazione', + es: 'Docker-Documentación', + pl: 'Dokumentacja dokerów', + uk: 'Документація', + 'zh-cn': 'Docker 文档', + }, + }, + ], + installedVersion: '3.0.22', + host: 'NanoPi-R5S', + installedFrom: 'iobroker.backitup@3.0.22', + tier: 2, + licenseInformation: { + license: 'MIT', + type: 'free', + }, + }, + native: { + minimalEnabled: true, + minimalTime: '02:40', + minimalEveryXDays: '1', + minimalDeleteAfter: '10', + minimalNameSuffix: '', + redisMinimalEnabled: false, + mysqlMinimalEnabled: false, + mysqlQuick: false, + mysqlSingleTransaction: false, + ccuEnabled: true, + ccuTime: '01:30', + ccuEveryXDays: '3', + ccuDeleteAfter: '10', + ccuNameSuffix: '', + ccuHost: '192.168.178.74', + ccuUser: 'Admin', + ccuPassword: '_W\u0004\u0016W\\T\u0017', + ccuMulti: false, + ccuEvents: [], + ccuUsehttps: false, + ccuSignedCertificates: true, + webdavEnabled: false, + webdavUsername: 'username', + webdavPassword: '', + webdavURL: 'https://example.com/remote.php/dav/files/username/', + webdavDeleteOldBackup: false, + webdavOwnDir: false, + webdavMinimalDir: '/backupDir/iobroker', + webdavCcuDir: '/backupDir/ccu', + webdavDir: '/backupDir', + webdavSignedCertificates: true, + dropboxEnabled: false, + dropboxAccessToken: '', + dropboxAccessJson: '', + dropboxTokenType: 'custom', + dropboxCodeChallenge: '', + dropboxDeleteOldBackup: false, + dropboxOwnDir: false, + dropboxMinimalDir: '/backupDir/iobroker', + dropboxCcuDir: '/backupDir/ccu', + dropboxDir: '/backupDir', + onedriveEnabled: false, + onedriveAccessJson: '', + onedriveDeleteOldBackup: false, + onedriveOwnDir: false, + onedriveMinimalDir: 'backupDir/iobroker', + onedriveCcuDir: 'backupDir/ccu', + onedriveDir: 'backupDir', + googledriveEnabled: true, + googledriveAccessTokens: + 'eyJhY2Nlc3NfdG9rZW4iOiJ5YTI5LmEwQVdZN0NrbVJYSWNBM3k5WDcwRlUzdkRLU1BLdTZKOW5oMUUzRV9aWTZHZFVXV2h0MzhFM3BUSWQ5ZWxWY1VtZDFzMDQ4Si1wc2Z0YlVSZXVKQVNFWHM2bVdXMkdGU3oxNDJ5cnRBSWFncktiQVIyV1JVZ194S2ppbWJEMmVnUmRLUExtNkM4ZlR5QlZCaV9hcVhtd2VBRWNBSDhLYUNnWUtBZm9TQVJNU0ZRRzF0RHJwaEt1UUtjRWw4UjNfa0hFT0pKWDlYZzAxNjMiLCJyZWZyZXNoX3Rva2VuIjoiMS8vMDNmMGJjOUxDcERnSkNnWUlBUkFBR0FNU053Ri1MOUlyc0VMdUF5ZFpZb1E0M0hVblpRZEh1N1pRaUJNcjlTWUl3TlIwUFF2OFRqbG1XbHhiSmtNMjA1aEMzak1JbzJPNW83ZyIsInNjb3BlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9kcml2ZSIsInRva2VuX3R5cGUiOiJCZWFyZXIiLCJleHBpcnlfZGF0ZSI6MTY4NjQ3ODg5MjQ4Mn0=', + googledriveDeleteOldBackup: false, + googledriveOwnDir: false, + googledriveMinimalDir: '/backupDir/iobroker', + googledriveCcuDir: '/backupDir/ccu', + googledriveDir: '/backupDir', + mySqlEnabled: false, + mySqlHost: 'localhost', + mySqlPort: '3306', + mySqlName: 'iobroker', + mySqlUser: '', + mySqlPassword: '', + mySqlDeleteAfter: 5, + mySqlDumpExe: '', + mySqlMulti: false, + mySqlEvents: [], + influxDBEnabled: false, + influxDBHost: 'localhost', + influxDBPort: '8088', + influxDBName: 'iobroker', + influxDBDumpExe: '', + influxDBDeleteAfter: 5, + influxDBType: 'local', + influxDBToken: '', + influxDBVersion: '1.x', + influxDBProtocol: 'http', + influxDBMulti: false, + influxDBEvents: [], + deleteOldDataBase: false, + grafanaEnabled: false, + grafanaHost: '', + grafanaPort: '3000', + grafanaUsername: 'admin', + grafanaPassword: '', + grafanaApiKey: '', + grafanaProtocol: 'http', + grafanaSignedCertificates: true, + pgSqlHost: '', + pgSqlPort: '5432', + pgSqlName: '', + pgSqlUser: '', + pgSqlPassword: '', + pgSqlDeleteAfter: 5, + pgSqlDumpExe: '', + pgSqlEnabled: false, + pgSqlMulti: false, + pgSqlEvents: [], + cifsEnabled: false, + cifsMount: '', + cifsUser: '', + cifsPassword: '', + cifsOwnDir: false, + cifsDomain: '', + cifsDir: 'sharename/backupDir', + cifsCcuDir: 'sharename/backupDir', + cifsMinimalDir: 'sharename/backupDir', + cifsDeleteOldBackup: false, + connectType: 'NFS', + smbType: 'vers=3.1.1', + sudoMount: true, + noserverino: false, + wakeOnLAN: false, + macAd: '20:DE:20:DE:20:DE', + wolWait: '25', + ftpEnabled: false, + ftpHost: '', + ftpPort: '21', + ftpSecure: false, + ftpDir: '/backupDir', + ftpUser: '', + ftpPassword: '', + ftpOwnDir: false, + ftpCcuDir: '/backupDir/ccu', + ftpMinimalDir: '/backupDir/iobroker', + ftpDeleteOldBackup: false, + redisEnabled: false, + redisPath: '/var/lib/redis', + redisType: 'local', + redisHost: '', + redisPort: '6379', + redisUser: '', + redisPassword: '', + redisAOFactive: false, + historyEnabled: false, + historyPath: 'media/usb/history', + javascriptsEnabled: false, + zigbeeEnabled: false, + yahkaEnabled: false, + jarvisEnabled: false, + notificationEnabled: false, + notificationsType: 'Telegram', + telegramInstance: 'telegram.0', + telegramNoticeType: 'longTelegramNotice', + telegramUser: 'allTelegramUsers', + telegramSilentNotice: false, + telegramOnlyError: false, + telegramWaitToSend: '0', + whatsappInstance: '', + whatsappNoticeType: 'longWhatsappNotice', + whatsappOnlyError: false, + whatsappWaitToSend: '0', + signalInstance: '', + signalNoticeType: 'longSignalNotice', + signalOnlyError: false, + signalWaitToSend: '0', + matrixInstance: '', + matrixNoticeType: 'longMatrixNotice', + matrixOnlyError: false, + matrixWaitToSend: '0', + pushoverInstance: '', + pushoverNoticeType: 'longPushoverNotice', + pushoverSilentNotice: false, + pushoverDeviceID: '', + pushoverOnlyError: false, + pushoverWaitToSend: '0', + emailReceiver: 'xxx@xxx.com', + emailSender: 'xxx@xxx.com', + emailInstance: '', + emailNoticeType: 'longEmailNotice', + emailOnlyError: false, + emailWaitToSend: '0', + debugLevel: false, + sentry_enable: true, + historyEntriesNumber: '25', + restoreSource: 'local', + startAllRestore: false, + hostType: 'Single', + slaveInstance: [], + slaveNameSuffix: '', + stopSlaveAfter: false, + ignoreErrors: false, + restoreTab: false, + noderedEnabled: false, + sqliteEnabled: false, + sqlitePath: '/opt/sqlite/data.db', + sqliteDumpExe: '', + zigbee2mqttPath: '/opt/zigbee2mqtt/data', + zigbee2mqttEnabled: false, + fileSizeError: '512', + fileSizeWarning: '1024', + ftpSignedCertificates: true, + onedriveLastTokenRenew: '', + wolPort: 9, + wolExtra: false, + discordInstance: 'discord.0', + discordNoticeType: 'longWhatsappNotice', + discordOnlyError: false, + discordWaitToSend: 0, + discordTarget: '', + cacheLoose: false, + ccuCron: false, + ccuCronJob: '00 36 01 */3 * *', + esphomeEnabled: false, + expertMount: + 'sudo mount -t cifs -o username=,password="",noserverino,cache=loose,rw,uid=iobroker,gid=iobroker,file_mode=0777,dir_mode=0777,vers=3.1.1 //192.168.0.1/NAS/BACKUP /opt/iobroker/backups', + gotifyInstance: 'gotify.0', + gotifyNoticeType: 'longGotifyNotice', + gotifyOnlyError: false, + gotifyWaitToSend: 0, + iobrokerCron: false, + iobrokerCronJob: '00 48 02 */1 * *', + advancedDelete: false, + dropboxDeleteAfter: 10, + ftpDeleteAfter: 10, + googledriveDeleteAfter: 10, + onedriveDeleteAfter: 10, + webdavDeleteAfter: 10, + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1726366593490, + protectedNative: [ + 'cifsPassword', + 'mySqlPassword', + 'ccuPassword', + 'ftpPassword', + 'grafanaPassword', + 'pgSqlPassword', + 'redisPassword', + 'webdavPassword', + ], + encryptedNative: [ + 'cifsPassword', + 'mySqlPassword', + 'ccuPassword', + 'ftpPassword', + 'grafanaPassword', + 'pgSqlPassword', + 'redisPassword', + 'webdavPassword', + ], + notifications: [ + { + scope: 'backitup', + name: { + en: 'Backitup', + de: 'Backitup', + ru: 'Backitup', + pt: 'Backitup', + nl: 'Backitup', + fr: 'Backitup', + it: 'Backitup', + es: 'Backitup', + pl: 'Backitup', + uk: 'Backitup', + 'zh-cn': 'Backitup', + }, + description: { + en: 'These notifications report errors when creating backups', + de: 'Diese Benachrichtigungen melden Fehler bei der Erstellung von Backups', + ru: 'Эти уведомления сообщают об ошибках при создании резервных копий', + pt: 'Estas notificações relatam erros ao criar backups', + nl: 'Deze meldingen rapporteren fouten bij het aanmaken van back-ups', + fr: 'Ces notifications signalent des erreurs lors de la création de sauvegardes', + it: 'Queste notifiche segnalano errori durante la creazione di backup', + es: 'Estas notificaciones reportan errores al crear copias de seguridad', + pl: 'Te powiadomienia zgłaszają błędy podczas tworzenia kopii zapasowych', + uk: 'Ці помилки звіту про повідомлення при створенні резервних копій', + 'zh-cn': '这些通知在创建备份时报告错误', + }, + categories: [ + { + category: 'backupError', + name: { + en: 'Error during backup creation', + de: 'Fehler bei der Backup-Erstellung', + ru: 'Ошибка при создании резервного копирования', + pt: 'Erro durante a criação de backup', + nl: 'Fout tijdens aanmaken van reservekopie', + fr: 'Erreur lors de la création de sauvegarde', + it: 'Errore durante la creazione di backup', + es: 'Error durante la creación de respaldo', + pl: 'Błąd podczas tworzenia kopii zapasowej', + uk: 'Помилка при створенні резервних копій', + 'zh-cn': '备份创建时出错', + }, + severity: 'alert', + description: { + en: 'Backitup has problems with the creation of backups. Please check the configuration and the debug log of the Backitup Adapter', + de: 'Backitup hat Probleme mit der Erstellung von Backups. Bitte überprüfen Sie die Konfiguration und das Debug-Log des Backitup Adapters', + ru: 'Backitup имеет проблемы с созданием резервных копий. Пожалуйста, проверьте конфигурацию и журнал отладки адаптера резервного копирования', + pt: 'Backitup tem problemas com a criação de backups. Por favor, verifique a configuração e o log de depuração do Adaptador Backitup', + nl: 'Backitup heeft problemen met het creëren van back-ups. Controleer de configuratie en het debuglog van de backitup-adapter', + fr: "Backitup a des problèmes avec la création de sauvegardes. Veuillez vérifier la configuration et le journal de débogage de l'adaptateur de sauvegarde", + it: "Backitup ha problemi con la creazione di backup. Si prega di controllare la configurazione e il registro debug dell'adattatore Backitup", + es: 'El respaldo tiene problemas con la creación de copias de seguridad. Por favor, compruebe la configuración y el registro de depuración del adaptador de copia de seguridad', + pl: 'Kopiowanie ma problemy z tworzeniem kopii zapasowych. Proszę sprawdzić konfigurację i dziennik debugowania adaptera Backitup', + uk: 'Backitup має проблеми з створенням резервних копій. Будь ласка, перевірте конфігурацію та дебюговий журнал адаптера Backitup', + 'zh-cn': '备份在创建备份方面有问题. 请检查备份适配器的配置和调试日志', + }, + regex: [], + limit: 1, + }, + { + category: 'onedriveWarn', + name: { + en: 'Error when creating the RefreshToken', + de: 'Fehler beim Erstellen des RefreshToken', + ru: 'Ошибка при создании RefreshToken', + pt: 'Erro ao criar o RefreshToken', + nl: 'Fout bij het aanmaken van de RefreshToken', + fr: 'Erreur lors de la création du RefreshToken', + it: 'Errore durante la creazione di RefreshToken', + es: 'Error al crear el RefreshToken', + pl: 'Błąd podczas tworzenia RefreshToken', + uk: 'Помилка при створенні RefreshToken', + 'zh-cn': '创建刷新工具时出错', + }, + severity: 'alert', + description: { + en: 'The OneDrive RefreshToken could not be updated. Please try to refresh the token manually.', + de: 'Der OneDrive RefreshToken konnte nicht aktualisiert werden. Bitte versuchen Sie, den Token manuell zu aktualisieren.', + ru: 'OneDrive RefreshToken не мог быть обновлен. Пожалуйста, попробуйте обновить токен вручную.', + pt: 'O OneDrive RefreshToken não pode ser atualizado. Por favor, tente atualizar o token manualmente.', + nl: 'De OneDrive RefreshToken kon niet worden bijgewerkt. Probeer het token handmatig te vernieuwen.', + fr: "Le OneDrive RefreshToken n'a pas pu être mis à jour. Veuillez essayer de rafraîchir le jeton manuellement.", + it: 'Il OneDrive RefreshToken non poteva essere aggiornato. Si prega di cercare di aggiornare manualmente il token.', + es: 'El OneDrive RefreshToken no puede ser actualizado. Por favor, intenta refrescar la ficha manualmente.', + pl: 'Nie można było zaktualizować OneDrive RefreshToken. Proszę spróbować odświeżać token ręcznie.', + uk: 'OneDrive RefreshToken не може бути оновлено. Будь ласка, спробуйте оновити токени вручну.', + 'zh-cn': '无法更新 OneDrive 刷新托肯 。 请尝试手动刷新符号 .', + }, + regex: [], + limit: 1, + }, + ], + }, + ], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'info.latestBackup', + type: 'state', + common: { + role: 'state', + name: 'Latest backup found by start', + type: 'json', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'info.ccuNextTime', + type: 'state', + common: { + role: 'state', + name: 'Next CCU backup', + type: 'string', + read: true, + write: false, + def: 'none', + }, + native: {}, + }, + { + _id: 'info.iobrokerNextTime', + type: 'state', + common: { + role: 'state', + name: 'Next iobroker backup', + type: 'string', + read: true, + write: false, + def: 'none', + }, + native: {}, + }, + { + _id: 'history', + type: 'channel', + common: { + name: 'History Logs', + }, + native: {}, + }, + { + _id: 'history.html', + type: 'state', + common: { + role: 'html', + name: 'History-Log of executed backups', + type: 'string', + read: true, + write: false, + def: 'No backups yet', + }, + native: {}, + }, + { + _id: 'history.json', + type: 'state', + common: { + role: 'state', + name: 'History-Log of executed backups', + type: 'json', + read: true, + write: false, + def: '[]', + }, + native: {}, + }, + { + _id: 'history.ccuLastTime', + type: 'state', + common: { + role: 'state', + name: 'Last CCU backup', + type: 'string', + read: true, + write: false, + def: 'No backups yet', + }, + native: {}, + }, + { + _id: 'history.iobrokerLastTime', + type: 'state', + common: { + role: 'state', + name: 'Last iobroker backup', + type: 'string', + read: true, + write: false, + def: 'No backups yet', + }, + native: {}, + }, + { + _id: 'history.ccuSuccess', + type: 'state', + common: { + role: 'switch', + name: 'Last ccu backup Success', + type: 'boolean', + read: true, + write: true, + def: false, + }, + native: {}, + }, + { + _id: 'history.iobrokerSuccess', + type: 'state', + common: { + role: 'switch', + name: 'Last iobroker backup Success', + type: 'boolean', + read: true, + write: true, + def: false, + }, + native: {}, + }, + { + _id: 'oneClick', + type: 'channel', + common: { + name: 'OneClick Buttons', + }, + native: {}, + }, + { + _id: 'oneClick.ccu', + type: 'state', + common: { + role: 'switch', + name: 'Execute CCU backup', + type: 'boolean', + read: true, + write: true, + def: false, + }, + native: {}, + }, + { + _id: 'oneClick.iobroker', + type: 'state', + common: { + role: 'switch', + name: 'Execute iobroker backup', + type: 'boolean', + read: true, + write: true, + def: false, + }, + native: {}, + }, + { + _id: 'output', + type: 'channel', + common: { + name: 'Output states', + }, + native: {}, + }, + { + _id: 'output.line', + type: 'state', + common: { + role: 'state', + name: 'Used for debug outputs', + type: 'string', + read: true, + write: false, + def: '', + }, + native: {}, + }, + ], + objects: [], + acl: { + object: 1636, + state: 1636, + file: 1632, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + user: 'system.user.admin', + }, + 'system.adapter.javascript.0': { + _id: 'system.adapter.javascript.0', + type: 'instance', + common: { + name: 'javascript', + title: 'Script Engine', + titleLang: { + en: 'Script Engine', + de: 'Skriptausführung', + ru: 'Скрипты', + pt: 'Script Engine', + nl: 'Script-engine', + fr: 'Moteur de script', + it: 'Motore di script', + es: 'Motor de script', + pl: 'Silnik skryptowy', + 'zh-cn': '脚本引擎', + uk: 'Механізм сценаріїв', + }, + authors: [ + 'bluefox ', + 'hobbyquaker ', + 'Apollon77 ', + 'AlCalzone ', + 'Matthias Kleine ', + ], + version: '8.8.3', + desc: { + en: 'Javascript/Blockly Script Engine for ioBroker', + de: 'Javascript/Blockly Skriptausführung für ioBroker', + ru: 'Выполнение Javascript/Blockly скриптов для ioBroker', + pt: 'Mecanismo Javascript/Blockly Script para ioBroker', + nl: 'Javascript/Blockly Script-engine voor ioBroker', + fr: 'Moteur de script Javascript/Blockly pour ioBroker', + it: 'Motore di script Javascript/Blockly per ioBroker', + es: 'Motor de secuencias de comandos Javascript/Blockly para ioBroker', + pl: 'Silnik skryptów JavaScript/Blockly dla ioBroker', + uk: 'Javascript/Blockly Script Engine для ioBroker', + 'zh-cn': 'ioBroker 的 Javascript/Blockly 脚本引擎', + }, + platform: 'Javascript/Node.js', + mode: 'daemon', + loglevel: 'info', + icon: 'javascript.png', + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.javascript/master/admin/javascript.png', + keywords: ['js', 'javascript', 'typescript', 'rules', 'automate', 'scriptengine', 'blockly', 'blokly'], + materialize: true, + readme: 'https://github.com/iobroker/ioBroker.javascript/blob/master/README.md', + enabled: true, + license: 'MIT', + compact: true, + eraseOnUpload: true, + adminTab: { + singleton: true, + name: { + en: 'Scripts', + de: 'Skripte', + ru: 'Скрипты', + }, + }, + docs: { + en: ['docs/en/README.md', 'docs/en/blockly.md', 'docs/en/javascript.md', 'docs/en/upgrade-guide.md'], + ru: ['docs/ru/README.md', 'docs/ru/blockly.md'], + de: ['docs/de/README.md', 'docs/de/blockly.md', 'docs/de/usage.md'], + }, + dependencies: [ + { + 'js-controller': '>=5.0.0', + }, + ], + globalDependencies: [ + { + admin: '>=5.1.28', + }, + ], + type: 'logic', + messagebox: true, + logTransporter: true, + plugins: { + sentry: { + dsn: 'https://f3b9740caaee4ee69eb68019d71526ff@sentry.iobroker.net/15', + }, + }, + tier: 1, + connectionType: 'none', + dataSource: 'none', + messages: [ + { + condition: { + operand: 'and', + rules: ['oldVersion<5.5.0', 'newVersion>=5.5.0'], + }, + title: { + en: 'Check used script mirror path!', + de: 'Überprüfen Sie den verwendeten Skript-Spiegelpfad!', + ru: 'Проверьте используемый путь к зеркалу скрипта!', + pt: 'Verifique o caminho do espelho de script usado!', + nl: 'Controleer het gebruikte scriptspiegelpad!', + fr: 'Vérifiez le chemin du miroir de script utilisé !', + it: 'Controlla il percorso del mirror dello script utilizzato!', + es: '¡Compruebe la ruta del espejo del script usado!', + pl: 'Sprawdź używaną ścieżkę lustrzaną skryptu!', + 'zh-cn': '检查使用的脚本镜像路径!', + uk: 'Перевірте використаний шлях дзеркала сценарію!', + }, + text: { + en: 'If the script mirror feature is used to save scripts also in the file system and a directory inside the ioBroker directory is configured, then you need to check if this mirroring location is still allowed! If not the adapter logs an error on startup and mirroring is deactivated! For a list of forbidden locations please check the adapter Readme.', + de: 'Wenn die Skript-Spiegelungsfunktion verwendet wird, um Skripte auch im Dateisystem zu speichern, und ein Verzeichnis innerhalb des ioBroker-Verzeichnisses konfiguriert ist, muss geprüft werden, ob dieser Spiegelungsspeicherort noch zulässig ist! Andernfalls meldet der Adapter beim Start einen Fehler und die Spiegelung wird deaktiviert! Eine Liste verbotener Orte ist in der Adapter-Readme zu finden.', + ru: 'Если функция зеркалирования скриптов используется для сохранения скриптов также в файловой системе и настроен каталог внутри каталога ioBroker, то вам необходимо проверить, разрешено ли это местоположение зеркалирования! В противном случае адаптер регистрирует ошибку при запуске, и зеркалирование деактивируется! Список запрещенных мест см. в файле Readme адаптера.', + pt: 'Se o recurso de espelhamento de script for usado para salvar scripts também no sistema de arquivos e um diretório dentro do diretório ioBroker estiver configurado, você precisará verificar se esse local de espelhamento ainda é permitido! Caso contrário, o adaptador registra um erro na inicialização e o espelhamento é desativado! Para obter uma lista de locais proibidos, verifique o Readme do adaptador.', + nl: 'Als de functie voor het spiegelen van scripts wordt gebruikt om scripts ook in het bestandssysteem op te slaan en een map in de ioBroker-map is geconfigureerd, moet u controleren of deze spiegellocatie nog steeds is toegestaan! Als dit niet het geval is, registreert de adapter een fout bij het opstarten en is spiegelen gedeactiveerd! Raadpleeg de adapter Readme voor een lijst met verboden locaties.', + fr: "Si la fonctionnalité de mise en miroir des scripts est utilisée pour enregistrer également les scripts dans le système de fichiers et qu'un répertoire à l'intérieur du répertoire ioBroker est configuré, vous devez vérifier si cet emplacement de mise en miroir est toujours autorisé ! Si ce n'est pas le cas, l'adaptateur enregistre une erreur au démarrage et la mise en miroir est désactivée ! Pour une liste des emplacements interdits, veuillez consulter le fichier Readme de l'adaptateur.", + it: "Se la funzione di mirroring degli script viene utilizzata per salvare gli script anche nel file system ed è configurata una directory all'interno della directory di ioBroker, è necessario verificare se questa posizione di mirroring è ancora consentita! In caso contrario, l'adattatore registra un errore all'avvio e il mirroring è disattivato! Per un elenco delle posizioni vietate, controllare il file Readme dell'adattatore.", + es: 'Si la función de duplicación de secuencias de comandos se utiliza para guardar secuencias de comandos también en el sistema de archivos y se configura un directorio dentro del directorio de ioBroker, ¡entonces debe verificar si esta ubicación de duplicación todavía está permitida! De lo contrario, el adaptador registra un error al iniciarse y la duplicación se desactiva. Para obtener una lista de ubicaciones prohibidas, consulte el archivo Léame del adaptador.', + pl: 'Jeśli funkcja kopii lustrzanej skryptów jest używana do zapisywania skryptów również w systemie plików, a katalog w katalogu ioBroker jest skonfigurowany, musisz sprawdzić, czy ta lokalizacja kopii lustrzanej jest nadal dozwolona! Jeśli nie, adapter rejestruje błąd podczas uruchamiania, a dublowanie jest wyłączone! Listę zabronionych lokalizacji można znaleźć w pliku Readme adaptera.', + 'zh-cn': + '如果使用脚本镜像功能将脚本也保存在文件系统中,并且配置了 ioBroker 目录内的目录,那么您需要检查该镜像位置是否仍然允许!如果不是,适配器会在启动时记录错误并且镜像被禁用!有关禁止位置的列表,请查看适配器自述文件。', + uk: 'Якщо функція дзеркала сценаріїв використовується для збереження сценаріїв також у файловій системі та налаштовано каталог у каталозі ioBroker, тоді вам потрібно перевірити, чи це розташування дзеркала все ще дозволено! Якщо ні, адаптер реєструє помилку під час запуску, і дзеркальне відображення вимикається! Щоб отримати список заборонених розташувань, перегляньте Readme адаптера.', + }, + link: 'https://github.com/ioBroker/ioBroker.javascript#forbidden-directories-for-script-filesystem-mirroring', + level: 'warn', + linkText: { + en: 'List of the forbidden Mirror locations', + de: 'Liste der verbotenen Mirror-Standorte', + ru: 'Список запрещенных локаций Зеркала', + pt: 'Lista dos locais de espelho proibidos', + nl: 'Lijst met de verboden Mirror-locaties', + fr: 'Liste des emplacements Mirror interdits', + it: 'Elenco delle posizioni degli specchi proibiti', + es: 'Lista de las ubicaciones de Mirror prohibidas', + pl: 'Lista zakazanych lokalizacji Lustrzanych', + 'zh-cn': '禁止镜像位置列表', + uk: 'Список заборонених місць розміщення дзеркал', + }, + buttons: ['agree', 'cancel'], + }, + { + condition: { + operand: 'and', + rules: ['oldVersion<7.0.0', 'newVersion>=7.0.0'], + }, + title: { + en: 'Small breaking change by usage of jsonata', + de: 'Kleine Breaking-Änderung durch Verwendung von jsonata', + ru: 'Небольшое изменение, вызванное использованием jsonata', + pt: 'Pequena alteração de quebra por uso de jsonata', + nl: 'Kleine breaking change door gebruik van jsonata', + fr: 'Petite modification de rupture en utilisant jsonata', + it: 'Piccola modifica di breaking utilizzando jsonata', + es: 'Pequeño cambio de ruptura por uso de jsonata', + pl: 'Mała zmiana w użyciu jsonata', + 'zh-cn': '使用 jsonata 的小破坏性变化', + uk: 'Невелика критична зміна через використання jsonata', + }, + text: { + en: 'All usages of jsonata must be rewritten to use promises. All blockly scripts with jsonata blocks must de changed (just move some blocks) and saved anew.', + de: 'Alle Verwendungen von jsonata müssen umgeschrieben werden, um Promises zu verwenden. Alle Blockly-Skripte mit jsonata-Blöcken müssen geändert werden (nur einige Blöcke verschieben) und neu gespeichert.', + ru: 'Все использования jsonata должны быть переписаны c использованием promises. Все скрипты с блоками jsonata в Blockly должны быть изменены (просто переместите некоторые блоки) и сохранены заново.', + pt: 'Todas as utilizações de jsonata devem ser reescritas para usar promessas. Todos os scripts do bloco de blocos com blocos jsonata devem ser alterados (basta mover alguns blocos) e salvos novamente.', + nl: 'Alle gebruiken van jsonata moeten worden herschreven om beloften te gebruiken. Alle blokly-schripten met jsonata-blokken moeten worden gewijzigd (verplaats gewoon enkele blokken) en opnieuw worden opgeslagen.', + fr: 'Toutes les utilisations de jsonata doivent être réécrites pour utiliser des promesses. Tous les scripts Blockly avec des blocs jsonata doivent être modifiés (déplacez simplement certains blocs) et enregistrés à nouveau.', + it: 'Tutti gli utilizzi di jsonata devono essere riscritti per utilizzare le promesse. Tutti gli script Blockly con blocchi jsonata devono essere modificati (spostare solo alcuni blocchi) e salvati di nuovo.', + es: 'Todos los usos de jsonata deben reescribirse para usar promesas. Todos los scripts de bloques de bloques con bloques jsonata deben cambiarse (solo mueve algunos bloques) y guardarse de nuevo.', + pl: 'Wszystkie użycia jsonata muszą zostać przepisane, aby korzystać z obietnic. Wszystkie skrypty blokowe z blokami jsonata muszą zostać zmienione (przeciągnij kilka bloków) i zapisane ponownie.', + 'zh-cn': + '所有 jsonata 的用法都必须重写以使用承诺。所有具有 jsonata 块的 Blockly 脚本都必须更改(只需移动一些块)并重新保存。', + uk: 'Усі використання jsonata потрібно переписати, щоб використовувати обіцянки. Усі блочні сценарії з блоками jsonata потрібно змінити (просто перемістити деякі блоки) і зберегти заново.', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + }, + { + condition: { + operand: 'and', + rules: ['oldVersion<7.5.0', 'newVersion>=7.5.0'], + }, + title: { + en: 'Check your Blockly scripts', + de: 'Überprüfen Sie Ihre Blockly-Skripte', + ru: 'Проверьте свой Блочные скрипты', + pt: 'Verifique o seu scripts em bloco', + nl: 'Controleer het. Blockly scripts', + fr: 'Vérifiez scripts en bloc', + it: 'Controlla il tuo Scrittori bloccati', + es: 'Revisa tu scripts bloqueados', + pl: 'Czujesz! skrypt Blockly', + uk: 'Перевірити Блокнотні скрипти', + 'zh-cn': '检查 法定说明', + }, + text: { + en: 'Some Blockly blocks have returned 0 instead of 7 for Sunday (when determining the day of the week). Please check all Blockly scripts that use the current day of the week as a numerical value. The week ranges from 1 (Monday) to 7 (Sunday), as described in the documentation.', + de: 'Einige Blockly-Bausteine haben 0 statt 7 für Sonntag (bei der Bestimmung des Tages der Woche) zurückgegeben. Bitte überprüfen Sie alle Blockly-Skripte, welche den aktuellen Tag der Woche als Zahlenwert verwenden. Die Woche beginnt bei 1 (Montag) bis 7 (Sonntag), wie in der Dokumentation beschrieben.', + ru: 'Некоторые блоки Blockly вернули 0 вместо 7 в воскресенье при определении дня недели. Пожалуйста, проверьте все Blockly скрипты, которые используют текущий день недели как числовое значение. Неделя колеблется от 1 (понедельник) до 7 (воскресенье), как описано в документации.', + pt: 'Alguns blocos Blockly retornaram 0 em vez de 7 para domingo ao determinar o dia da semana. Verifique todos os scripts Blockly que usam o dia atual da semana como um valor numérico. A semana varia de 1 (segunda-feira) a 7 (domingo), conforme descrito na documentação.', + nl: 'Sommige Blockly blokken hebben 0 teruggebracht in plaats van 7 voor zondag wanneer ze de dag van de week bepalen. Controleer alle Blockly scripts die de huidige dag van de week gebruiken als een numerische waarde. De wekelijkse bereik van 1 tot 7, zoals beschreven in de documentatie.', + fr: 'Certains blocs Blockly ont retourné 0 au lieu de 7 pour le dimanche lors de la détermination du jour de la semaine. Veuillez vérifier tous les scripts Blockly qui utilisent le jour actuel de la semaine comme valeur numérique. La semaine varie de 1 (le lundi) à 7 (le dimanche) comme décrit dans la documentation.', + it: 'Alcuni blocchi Blockly hanno restituito 0 invece di 7 per Domenica quando determina il giorno della settimana. Si prega di controllare tutti gli script Blockly che utilizzano il giorno corrente della settimana come valore numerico. La settimana varia da 1 (lunedì) a 7 (domenica) come descritto nella documentazione.', + es: 'Algunos bloques Blockly han devuelto 0 en lugar de 7 para el domingo al determinar el día de la semana. Por favor, compruebe todos los scripts Blockly que utilizan el día actual de la semana como un valor numérico. La semana va de 1 (lunes) a 7 (domingo), como se describe en la documentación.', + pl: 'Niektóre bloki Blockly wróciły zamiast 7 na niedzielę, gdy ustalono dzień tygodnia. Proszę sprawdzać wszystkie scenariusze Blockly, które wykorzystują bieżący dzień tygodnia jako wartość numeryczną. Tydzień to od 1 (poniedziałek) do 7 (dzisiejszy), co opisuje w dokumencie.', + uk: 'Деякі блоки блокнотів повернулися 0 замість 7 на неділю при визначенні дня тижня. Будь ласка, перевірте всі сценарії Blockly, які використовують поточний день тижня як чисельне значення. Щотижневий діапазон від 1 (понеділок) до 7 (неділя,) як описано в документації.', + 'zh-cn': + '在确定一周日时,一些锁定区已恢复了0而不是7天星期。 请检查使用本星期日作为微妙价值的所有固定文字。 如文件所述,该星期有1个(星期一)至7个(日)。.', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + }, + { + condition: { + operand: 'and', + rules: ['oldVersion<8.0.0', 'newVersion>=8.0.0'], + }, + title: { + en: 'Replace "request" functions after update', + de: '"Request"-Funktionen nach dem Update ersetzen', + ru: 'Заменить "запрос" функции после обновления', + pt: 'Substitua funções "request" após atualização', + nl: 'Vervang "verzoek" functies na update', + fr: 'Remplacer les fonctions « request » après mise à jour', + it: 'Sostituisci le funzioni "richiesta" dopo l\'aggiornamento', + es: 'Reemplazar funciones de "Solicitud" después de la actualización', + pl: 'Zastąp funkcje "request" po aktualizacji', + uk: 'Замініть функції "request" після оновлення', + 'zh-cn': '更新后替换“ request” 函数', + }, + text: { + en: 'It is required to update all scripts which use the "request" package! This package will be removed in future versions. Please use the new "Bockly" blocks for "httpGet" or use another library (like axios) in your JavaScript code.', + de: 'Es ist erforderlich, alle Skripte zu aktualisieren, die das "Request"-Paket verwenden! Dieses Paket wird in zukünftigen Versionen entfernt. Bitte nutze die neuen "Bockly"-Blöcke für "httpGet" oder nutze eine andere Bibliothek (wie axios) im JavaScript-Code.', + ru: 'Требуется обновить все скрипты, которые используют пакет «запроса»! Этот пакет будет удален в будущих версиях. Пожалуйста, используйте новые блоки «Bockly» для «httpGet» или используйте другую библиотеку (например, axios) в вашем коде JavaScript.', + pt: 'É necessário atualizar todos os scripts que usam o pacote "pedido"! Este pacote será removido em versões futuras. Por favor, use os novos blocos "Bockly" para "httpGet" ou use outra biblioteca (como axios) em seu código JavaScript.', + nl: 'Het is vereist om alle scripts die het "verzoek" pakket gebruiken te updaten! Dit pakket zal in toekomstige versies worden verwijderd. Gebruik de nieuwe blokken "Bockly" voor "httpGet" of gebruik een andere bibliotheek (zoals axios) in uw JavaScript-code.', + fr: 'Il est nécessaire de mettre à jour tous les scripts qui utilisent le paquet "request"! Ce paquet sera supprimé dans les versions futures. Veuillez utiliser les nouveaux blocs "Bockly" pour "httpGet" ou utiliser une autre bibliothèque (comme axios) dans votre code JavaScript.', + it: 'È necessario aggiornare tutti gli script che utilizzano il pacchetto "richiesta"! Questo pacchetto verrà rimosso nelle versioni future. Si prega di utilizzare i nuovi blocchi "Bockly" per "httpGet" o utilizzare un\'altra libreria (come gli assi) nel codice JavaScript.', + es: '¡Se requiere actualizar todos los scripts que utilizan el paquete "request"! Este paquete será eliminado en futuras versiones. Utilice los nuevos bloques "Bockly" para "httpGet" o utilice otra biblioteca (como axios) en su código JavaScript.', + pl: 'Wymagane jest uaktualnienie wszystkich skryptów, które korzystają z pakietu "request"! Ten pakiet zostanie usunięty w przyszłych wersjach. Proszę użyć nowych bloków "Bockly" dla "httpGet" lub użyć innej biblioteki (jak axios) w swoim kodzie JavaScript.', + uk: 'Щоб оновити всі скрипти, які використовують пакет "запит"! Цей пакет буде видалений в наступних версіях. Будь ласка, використовуйте нові блоки для "httpGet" або використовуйте іншу бібліотеку (наприклад, axios) у вашому JavaScript-коді.', + 'zh-cn': + '需要更新所有使用"请求"包的脚本! 这个软件包在未来的版本中将被删除. 请为“ httpGet” 使用新的“ Bockly” 块, 或者在您的 JavaScript 代码中使用另一个库( 如 axios) .', + }, + link: 'https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/upgrade-guide.md', + level: 'warn', + buttons: ['agree', 'cancel'], + }, + ], + installedFrom: 'iobroker.javascript@8.8.3', + installedVersion: '8.8.3', + host: 'NanoPi-R5S', + blockedVersions: ['8.0.0', '8.0.1'], + adminUI: { + config: 'json', + tab: 'html', + }, + licenseInformation: { + license: 'MIT', + type: 'free', + }, + }, + native: { + latitude: '', + longitude: '', + enableSetObject: true, + enableSendToHost: false, + enableExec: false, + libraries: '', + libraryTypings: '', + subscribe: true, + useSystemGPS: true, + mirrorPath: '', + mirrorInstance: '0', + allowSelfSignedCerts: false, + sunriseEvent: null, + sunriseOffset: '', + sunriseLimitStart: '06:00', + sunriseLimitEnd: '12:00', + sunsetEvent: 'dusk', + sunsetOffset: '', + sunsetLimitStart: '18:00', + sunsetLimitEnd: '23:00', + maxSetStatePerMinute: '1000', + gptKey: '', + createAstroStates: true, + maxTriggersPerScript: 100, + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1726362262951, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [ + { + scope: 'javascript', + name: { + en: 'Script Engine', + de: 'Skriptausführung', + ru: 'Скрипты', + pt: 'Script Engine', + nl: 'Script-engine', + fr: 'Moteur de script', + it: 'Motore di script', + es: 'Motor de script', + pl: 'Silnik skryptowy', + uk: 'Механізм сценаріїв', + 'zh-cn': '脚本引擎', + }, + description: { + en: 'Notifications generated by the script engine', + de: 'Benachrichtigungen, welche von der Skript-Engine generiert werden', + ru: 'Уведомления, генерируемые скриптовым двигателем', + pt: 'Notificações geradas pelo mecanismo de script', + nl: 'Door de script-engine gegenereerde meldingen', + fr: 'Notifications générées par le moteur de script', + it: 'Notifiche generate dal motore di script', + es: 'Notificaciones generadas por el motor script', + pl: 'Powiadomienia generowane przez silnik skryptu', + uk: 'Повідомлення, що генеруються двигуном скрипта', + 'zh-cn': '脚本引擎生成的通知', + }, + categories: [ + { + category: 'scriptMessage', + name: { + en: 'Message from script', + de: 'Nachricht von Skript', + ru: 'Сообщение от скрипта', + pt: 'Mensagem do script', + nl: 'Bericht van script', + fr: 'Message du script', + it: 'Messaggio dallo script', + es: 'Mensaje del script', + pl: 'Wiadomość ze skryptu', + uk: 'Повідомлення з сценарію', + 'zh-cn': '来自脚本的信件', + }, + severity: 'notify', + description: { + en: 'Custom message from scripts', + de: 'Benutzerdefinierte Nachricht von Skript', + ru: 'Пользовательское сообщение из скриптов', + pt: 'Mensagem personalizada de scripts', + nl: 'Aangepast bericht van scripts', + fr: 'Message personnalisé à partir de scripts', + it: 'Messaggi personalizzati da script', + es: 'Mensaje personalizado de scripts', + pl: 'Niestandardowa wiadomość ze skryptów', + uk: 'Спеціальне повідомлення від сценаріїв', + 'zh-cn': '自定义脚本中的消息', + }, + regex: [], + limit: 100, + }, + { + category: 'scriptAlert', + name: { + en: 'Alert from script', + de: 'Alarm von Skript', + ru: 'Объявление по сценарию', + pt: 'Alerta do script', + nl: 'Waarschuwing van script', + fr: 'Alerte du script', + it: 'Avviso da script', + es: 'Alerta del script', + pl: 'Alarm ze skryptu', + uk: 'Вставте з скрипта', + 'zh-cn': '从脚本发出警告', + }, + severity: 'alert', + description: { + en: 'Custom alert from scripts', + de: 'Benutzerdefinierte Warnung von Skript', + ru: 'Настраиваемое оповещение от скриптов', + pt: 'Alerta personalizado de scripts', + nl: 'Aangepaste waarschuwing van scripts', + fr: 'Alerte personnalisée des scripts', + it: 'Avviso personalizzato da script', + es: 'Alerta personalizada de scripts', + pl: 'Własny alarm ze skryptów', + uk: 'Користувальницькі сповіщення від сценаріїв', + 'zh-cn': '自定义脚本提醒', + }, + regex: [], + limit: 100, + }, + ], + }, + ], + instanceObjects: [ + { + _id: 'variables', + type: 'channel', + common: { + name: { + en: 'Useful variables', + de: 'Nützliche Variablen', + ru: 'Полезные переменные', + pt: 'Variáveis úteis', + nl: 'Gebruikelijke variabelen', + fr: 'Variables utiles', + it: 'Variazioni utili', + es: 'Variables útiles', + pl: 'Zmienny', + uk: 'Корисні зміни', + 'zh-cn': '使用变量', + }, + }, + native: {}, + }, + { + _id: 'variables.astro', + type: 'folder', + common: { + name: { + en: 'Sun movement', + de: 'Sonnenbewegung', + ru: 'Солнце движение', + pt: 'Movimento do sol', + nl: 'Sun beweging', + fr: 'Mouvement solaire', + it: 'Movimento solare', + es: 'Movimiento solar', + pl: 'Słońce', + uk: 'Сонячний рух', + 'zh-cn': 'A. 太阳运动', + }, + }, + native: {}, + }, + { + _id: 'variables.isDayTime', + type: 'state', + common: { + name: { + en: 'Is day time', + de: 'Ist Tag', + ru: 'Дневное время', + pt: 'É hora do dia', + nl: 'Is de dag', + fr: 'Le jour', + it: "È l'ora del giorno", + es: 'Es hora del día', + pl: 'Czasem', + uk: 'В день', + 'zh-cn': '日 日', + }, + type: 'boolean', + role: 'indicator', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'variables.isDaylightSaving', + type: 'state', + common: { + name: { + en: 'Is daylight saving time active', + de: 'Ist Sommerzeit aktiv', + ru: 'Является дневным светом экономия время активным', + pt: 'É hora de salvar a luz do dia ativo', + nl: 'Is daglichtbesparing', + fr: "Temps d'été actif", + it: 'È tempo di risparmio di luce del giorno attivo', + es: 'Es tiempo de ahorro de la luz del día activo', + pl: 'Czas wolny', + uk: 'Чи активна економія денного світла', + 'zh-cn': '导 言', + }, + type: 'boolean', + role: 'indicator', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'variables.dayTime', + type: 'state', + common: { + name: { + en: 'Current time', + de: 'Aktuelle Zeit', + ru: 'Текущее время', + pt: 'Tempo atual', + nl: 'Tijd om', + fr: 'Heure actuelle', + it: 'Ora attuale', + es: 'Hora actual', + pl: 'Czas bieżący', + uk: 'Поточний час', + 'zh-cn': '目前时间', + }, + type: 'string', + role: 'state', + read: true, + write: false, + }, + native: { + format12: false, + leadingZeros: true, + }, + }, + { + _id: 'variables.rulesTour', + type: 'state', + common: { + name: { + en: 'Tour completed', + de: 'Tour abgeschlossen', + ru: 'Тур завершен', + pt: 'Excursão concluída', + nl: 'Tour voltooid', + fr: 'Tour terminé', + it: 'Tour completato', + es: 'Tour completado', + pl: 'Tour', + uk: 'Тур завершено', + 'zh-cn': '完成的工作', + }, + type: 'boolean', + role: 'state', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'debug', + type: 'channel', + common: { + name: { + en: 'Debug variables', + de: 'Debug-Variablen', + ru: 'Переменные Debug', + pt: 'Variáveis de depuração', + nl: 'Debug variabelen', + fr: 'Débug variables', + it: 'Variabili del debito', + es: 'Variables de depuración', + pl: 'Zmienna debugowa', + uk: 'Debug змінні', + 'zh-cn': '变量', + }, + }, + native: {}, + }, + { + _id: 'debug.to', + type: 'state', + common: { + name: { + en: 'Send data to debugger', + de: 'Daten an debugger senden', + ru: 'Отправить данные для отладки', + pt: 'Enviar dados para depurador', + nl: 'Stuur gegevens naar debugger', + fr: 'Envoyer des données à debugger', + it: 'Invia i dati a debugger', + es: 'Enviar datos a depurador', + pl: 'Dane dotyczące debuggera', + uk: 'Надсилання даних на дебугер', + 'zh-cn': '黑暗数据', + }, + type: 'string', + role: 'json', + read: false, + write: true, + }, + native: {}, + }, + { + _id: 'debug.from', + type: 'state', + common: { + name: { + en: 'Data from debugger', + de: 'Daten von debugger', + ru: 'Данные от debugger', + pt: 'Dados do depurador', + nl: 'Data van debugger', + fr: 'Data from debugger', + it: 'Dati dal debugger', + es: 'Datos del depurador', + pl: 'Dane z debuggera', + uk: 'Дані з debugger', + 'zh-cn': 'A. 黑暗取的数据', + }, + type: 'string', + role: 'json', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'debug.rules', + type: 'state', + common: { + name: { + en: 'Data from rules logic', + de: 'Daten aus der Regellogik', + ru: 'Данные из логики правил', + pt: 'Dados da lógica de regras', + nl: 'Data van regels logica', + fr: 'Données de la logique des règles', + it: 'Dati dalla logica delle regole', + es: 'Datos de la lógica de las reglas', + pl: 'Dane z zakresu logiki', + uk: 'Дані з логіки правил', + 'zh-cn': '从规则逻辑数据', + }, + type: 'string', + role: 'json', + read: true, + write: false, + }, + native: {}, + }, + ], + objects: [ + { + _id: '_design/script', + type: 'design', + language: 'javascript', + views: { + javascript: { + map: "function(doc) { if (doc.type === 'script' && doc.common.engineType.match(/^[jJ]ava[sS]cript|^[cC]offee[sS]cript|^[tT]ype[sS]cript|^Blockly|^Rules/)) emit(doc.common.name, doc); }", + }, + }, + }, + { + _id: 'script.js', + type: 'device', + common: { + name: { + en: 'JavaScript', + de: 'JavaScript', + ru: 'JavaScript', + pt: 'JavaScript', + nl: 'JavaScrift', + fr: 'JavaScript', + it: 'JavaScript', + es: 'JavaScript', + pl: 'JavaScript', + uk: 'Про нас', + 'zh-cn': '瓦 兰', + }, + }, + native: {}, + }, + { + _id: 'script.js.common', + type: 'channel', + common: { + name: { + en: 'Common scripts (common)', + de: 'Allgemeine Skripte (common)', + ru: 'Общие скрипты (common)', + pt: 'Scripts comuns (common)', + nl: 'Common scripts (common)', + fr: 'Scénarios communs (common)', + it: 'Scrittori comuni (common)', + es: 'Scripts comunes (common)', + pl: 'Common script (common)', + uk: 'Загальні сценарії (common)', + 'zh-cn': '共同说明 (common)', + }, + }, + native: {}, + }, + { + _id: 'script.js.global', + type: 'channel', + common: { + name: { + en: 'Global scripts (global)', + de: 'Globale Skripte (global)', + ru: 'Глобальные скрипты (global)', + pt: 'Scripts globais (global)', + nl: 'Global scripts (global)', + fr: 'Scénarios mondiaux (global)', + it: 'Scrittori globali (global)', + es: 'Guiones globales (global)', + pl: 'Globalny scenariusz (global)', + uk: 'Глобальні сценарії (global)', + 'zh-cn': '全球说明 (global)', + }, + }, + native: {}, + }, + ], + user: 'system.user.admin', + }, + 'system.adapter.hm-rpc.0': { + _id: 'system.adapter.hm-rpc.0', + type: 'instance', + common: { + name: 'hm-rpc', + title: 'HomeMatic RF', + desc: { + en: 'Connects HomeMatic Interface-Processes (BidCos-Services, Homegear and CUxD) via XML-RPC or BIN-RPC to ioBroker', + de: 'Verbindet HomeMatic Interface-Prozesse (BidCos-Services, Homegear und CUxD) via XML-RPC oder BIN-RPC mit ioBroker', + ru: 'Подключает HomeMatic интерфейсы (BidCos-сервисы, Homegear и CUxD) через XML-RPC или BIN-RPC к ioBroker', + pt: 'Conecta HomeMatic Interface-Processes (BidCos-Services, Homegear e CUxD) via XML-RPC ou BIN-RPC para ioBroker', + nl: 'Verbindt HomeMatic Interface-processen (BidCos-Services, Homegear en CUxD) via XML-RPC of BIN-RPC met ioBroker', + fr: "Connecte les processus d'interface HomeMatic (BidCos-Services, Homegear et CUxD) via XML-RPC ou BIN-RPC à ioBroker", + it: "Collega l'interfaccia HomeMatic: i processi (BidCos-Services, Homegear e CUxD) tramite XML-RPC o BIN-RPC su ioBroker", + es: 'Conecta los Procesos de Interfaz HomeMatic (BidCos-Services, Homegear y CUxD) a través de XML-RPC o BIN-RPC a ioBroker', + pl: 'Łączy procesy HomeMatic-Interface (BidCos-Services, Homegear i CUxD) za pośrednictwem XML-RPC lub BIN-RPC z ioBroker', + 'zh-cn': + '通过 XML-RPC 或 BIN-RPC 将 HomeMatic 接口进程(BidCos-Services、Homegear 和 CUxD)连接到 ioBroker', + uk: 'Підключає HomeMatic інтерфейси (BidCos-сервіси, Homegear і CUxD) через XML-RPC або BIN-RPC до ioBroker', + }, + version: '2.0.2', + authors: ['hobbyquaker ', 'Moritz Heusinger '], + license: 'MIT', + mode: 'daemon', + platform: 'Javascript/Node.js', + loglevel: 'info', + readme: 'https://github.com/ioBroker/ioBroker.hm-rpc/blob/master/README.md', + icon: 'homematic.png', + materialize: true, + compact: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.hm-rpc/master/admin/homematic.png', + keywords: [ + 'homematic', + 'bidcos', + 'eq3', + 'ELV', + 'CCU', + 'CCU1', + 'CCU2', + 'rpc', + 'xmlrpc', + 'homegear', + 'binrpc', + 'CUxD', + 'FS20', + 'FHT', + 'HMS', + 'EnOcean', + ], + type: 'iot-systems', + connectionType: 'local', + dataSource: 'push', + stopTimeout: 1000, + messagebox: true, + supportStopInstance: false, + dependencies: [ + { + 'js-controller': '>=5.0.19', + }, + ], + plugins: { + sentry: { + dsn: 'https://1bc0c96f48e44483b283bc5fc0ca91e2@sentry.iobroker.net/10', + pathWhitelist: [], + errorBlacklist: ['SyntaxError'], + }, + }, + adminUI: { + config: 'json', + }, + titleLang: { + en: 'HomeMatic RPC', + de: 'HomeMatic RPC', + ru: 'HomeMatic RPC', + pt: 'HomeMatic RPC', + nl: 'HomeMatic RPC', + fr: 'HomeMatic RPC', + it: 'HomeMatic RPC', + es: 'HomeMatic RPC', + pl: 'HomeMatic RPC', + 'zh-cn': 'HomeMatic RPC', + uk: 'HomeMatic RPC', + }, + tier: 2, + installedFrom: 'iobroker.hm-rpc@2.0.2', + installedVersion: '2.0.2', + enabled: true, + host: 'NanoPi-R5S', + supportedMessages: { + deviceManager: true, + }, + globalDependencies: [ + { + admin: '>=6.0.0', + }, + ], + licenseInformation: { + license: 'MIT', + type: 'free', + link: 'https://github.com/ioBroker/ioBroker.hm-rpc/blob/master/LICENSE', + }, + messages: [ + { + condition: { + operand: 'and', + rules: ['oldVersion<1.17.0', 'newVersion>=1.17.0'], + }, + title: { + en: 'Reenter your credentials for https', + de: 'Geben Sie erneut Ihre Anmeldeinformationen für https ein', + ru: 'Восстановить свои учетные данные для https', + pt: 'Insira suas credenciais para https', + nl: 'Uw referenties voor https opnieuw invoeren', + fr: 'Entrez de nouveau vos identifiants pour https', + it: 'Reinserire le credenziali per https', + es: 'Ingrese sus credenciales para https', + pl: 'Wprowadź swoje referencje do https', + uk: 'Відновити свої облікові дані за посиланням', + 'zh-cn': '重新输入您的 https 证书', + }, + text: { + en: 'The internal encryption method has been changed. Please enter your username and password in the instance configuration again.', + de: 'Die interne Verschlüsselungsmethode wurde geändert. Bitte geben Sie Ihren Benutzernamen und Ihr Passwort erneut in der Instanzkonfiguration ein.', + ru: 'Был изменен внутренний метод шифрования. Пожалуйста, введите ваше имя пользователя и пароль в конфигурации экземпляра снова.', + pt: 'O método de criptografia interna foi alterado. Digite seu nome de usuário e senha na configuração da instância novamente.', + nl: 'De interne coderingsmethode is gewijzigd. Voer uw gebruikersnaam en wachtwoord in de instantieconfiguratie opnieuw in.', + fr: "La méthode de chiffrement interne a été modifiée. Veuillez à nouveau saisir votre nom d'utilisateur et votre mot de passe dans la configuration de l'instance.", + it: "Il metodo di crittografia interna è stato modificato. Inserisci nuovamente il nome utente e la password nella configurazione dell'istanza.", + es: 'El método de cifrado interno ha sido cambiado. Ingrese su nombre de usuario y contraseña en la configuración de instancia de nuevo.', + pl: 'Wewnętrzna metoda szyfrowania została zmieniona. Proszę podać nazwę użytkownika i hasło w konfiguracji instancji ponownie.', + uk: "Змінено метод внутрішнього шифрування. Будь ласка, введіть ім'я користувача та пароль в налаштуваннях екземпляра знову.", + 'zh-cn': '内部加密方法已经改变. 请在实例配置中再次输入您的用户名和密码 .', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + }, + ], + }, + native: { + homematicAddress: '192.168.178.74', + adapterAddress: '192.168.178.73', + homematicPort: '2001', + callbackAddress: '', + port: '0', + type: 'xml', + daemon: 'rfd', + checkInitInterval: '180', + reconnectInterval: '30', + forceReInit: false, + username: '', + password: '', + useHttps: false, + dontDelete: false, + }, + from: 'system.adapter.admin.0', + ts: 1727188165367, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['username', 'password'], + encryptedNative: ['username', 'password'], + notifications: [], + instanceObjects: [ + { + _id: 'updated', + type: 'state', + common: { + name: { + en: 'New devices added', + de: 'Neue Geräte hinzugefügt', + ru: 'Новые добавленные устройства', + pt: 'Novos dispositivos adicionados', + nl: 'Nieuwe apparaten toegevoegd', + fr: 'Nouveaux appareils ajoutés', + it: 'Nuovi dispositivi aggiunti', + es: 'Nuevos dispositivos añadidos', + pl: 'Dodano nowe urządzenia', + uk: 'Додані нові пристрої', + 'zh-cn': '新增设备', + }, + type: 'boolean', + read: true, + write: true, + }, + }, + { + _id: 'info', + type: 'channel', + common: { + name: { + en: 'Information', + de: 'Informationen', + ru: 'Информация', + pt: 'Informação', + nl: 'Informatie', + fr: 'Informations', + it: 'Informazioni', + es: 'Información', + pl: 'Informacje', + uk: 'Інформація', + 'zh-cn': '资料', + }, + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + name: { + en: 'Connected to CCU', + de: 'Verbindung mit CCU', + ru: 'Подключен к CCU', + pt: 'Conectado ao CCU', + nl: 'Verbonden met CCU', + fr: 'Connecté au CCU', + it: 'Collegato a CCU', + es: 'Conectado a la CCU', + pl: 'Połączone z CCU', + uk: 'Підключення до CCU', + 'zh-cn': '已连接到 CCU', + }, + type: 'boolean', + role: 'indicator.connected', + read: true, + write: false, + def: false, + }, + native: {}, + }, + ], + objects: [ + { + _id: '_design/hm-rpc', + type: 'design', + language: 'javascript', + views: { + listDevices: { + map: "function(doc) {\n if (doc._id.match(/^hm-rpc\\.[0-9]+\\.\\*?[A-Za-z0-9_-]+(\\.[0-9]+)?$/)) {\n emit(doc._id, {ADDRESS:(doc.native?doc.native.ADDRESS:''),VERSION:(doc.native?doc.native.VERSION:'')});\n }\n}", + }, + paramsetDescription: { + map: "function(doc) {\n if (doc._id.match(/^hm-rpc\\.meta/) && doc.meta.type === 'paramsetDescription') {\n emit(doc._id, doc);\n }\n}", + }, + }, + }, + ], + user: 'system.user.admin', + }, + 'system.adapter.hm-rega.0': { + _id: 'system.adapter.hm-rega.0', + type: 'instance', + common: { + name: 'hm-rega', + version: '5.1.0', + title: 'HomeMatic ReGaHSS', + titleLang: { + en: 'HomeMatic ReGaHSS', + de: 'HomeMatic ReGaHSS', + ru: 'HomeMatic ReGaHSS', + pt: 'HomeMatic ReGaHSS', + nl: 'HomeMatic ReGaHSS', + fr: 'AccueilMatic ReGaHSS', + it: 'HomeMatic ReGaHSS', + es: 'HomeMatic ReGaHSS', + pl: 'HomeMatic ReGaHSS', + 'zh-cn': 'HomeMatic ReGaHSS', + }, + desc: { + en: 'Connects HomeMatic CCU "Logic Layer" ("ReGaHSS") to ioBroker', + de: 'Verbindet die Logikschicht einer HomeMatic CCU ("ReGaHSS") mit ioBroker', + ru: 'Соединяет модуль логики системы Homematic CCU ("ReGaHSS") с ioBroker', + pt: 'Conecta o HomeMatic CCU "Layer Lógica" ("ReGaHSS") para ioBroker', + nl: 'Verbindt HomeMatic CCU "Logic Layer" ("ReGaHSS ") met ioBroker', + fr: 'Connecte HomeMatic CCU "Logic Layer" ("ReGaHSS") à ioBroker', + it: 'Collega HomeMatic CCU "Logic Layer" ("ReGaHSS") a ioBroker', + es: 'Conecta CCU HomeMatic "Capa lógica" ("ReGaHSS") a ioBroker', + pl: 'Łączy HomeMatic CCU "Logic Layer" ("ReGaHSS") z ioBroker', + 'zh-cn': '将 HomeMatic CCU“逻辑层”(“ReGaHSS”)连接到 ioBroker', + }, + dependencies: [ + 'hm-rpc', + { + 'js-controller': '>=4.0.0', + }, + ], + authors: [ + 'hobbyquaker ', + 'bluefox ', + 'Moritz Heusinger ', + ], + license: 'MIT', + mode: 'daemon', + platform: 'Javascript/Node.js', + loglevel: 'info', + materialize: true, + docs: { + en: 'README.md', + }, + readme: 'https://github.com/ioBroker/ioBroker.hm-rega/blob/master/README.md', + icon: 'homematic.png', + compact: true, + messagebox: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.hm-rega/master/admin/homematic.png', + keywords: ['homematic', 'eq3', 'regahss', 'ccu1', 'ccu2'], + localLinks: { + _default: '%webinterfaceProtocol%://%homematicAddress%:%webinterfacePort%', + }, + type: 'iot-systems', + connectionType: 'local', + dataSource: 'poll', + tier: 2, + plugins: { + sentry: { + dsn: 'https://08c0b6d9b71c43cc91e9705877681085@sentry.iobroker.net/11', + pathWhitelist: [], + errorBlacklist: ['SyntaxError'], + }, + }, + installedFrom: 'iobroker.hm-rega@5.1.0', + installedVersion: '5.1.0', + enabled: true, + host: 'NanoPi-R5S', + licenseInformation: { + license: 'MIT', + type: 'free', + }, + adminUI: { + config: 'materialize', + }, + }, + native: { + homematicAddress: '192.168.178.74', + homematicPort: 8181, + reconnectionInterval: '30', + polling: true, + pollingInterval: '30', + pollingTrigger: 'BidCoS-RF.50.PRESS_SHORT', + rfdEnabled: true, + rfdAdapter: 'hm-rpc.0', + hs485denabled: false, + hs485dAdapter: '', + cuxdEnabled: false, + cuxdAdapter: '', + hmipEnabled: true, + hmipAdapter: 'hm-rpc.1', + virtualDevicesEnabled: false, + virtualDevicesAdapter: '', + syncVariables: true, + syncPrograms: true, + syncNames: true, + syncRooms: true, + enumRooms: 'enum.rooms', + syncFunctions: true, + enumFunctions: 'enum.functions', + syncFavorites: true, + enumFavorites: 'enum.favorites', + username: '', + password: '', + useHttps: false, + showInvSysVar: false, + webinterfacePort: 80, + webinterfaceProtocol: 'http', + hs485dEnabled: false, + syncDutyCycle: false, + pollingIntervalDC: '', + }, + from: 'system.adapter.admin.0', + ts: 1727188164602, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['username', 'password'], + encryptedNative: [], + notifications: [ + { + scope: 'hm-rega', + name: { + en: 'HomeMatic ReGaHSS Adapter', + de: 'HomeMatic ReGaHSS Adapter', + ru: 'HomeMatic ReGaHSS Adapter', + pt: 'HomeMatic ReGaHSS Adapter', + nl: 'HomeMatic ReGaHSS Adapter', + fr: 'HomeMatic ReGaHSS Adapter', + it: 'HomeMatic ReGaHSS Adapter', + es: 'HomeMatic ReGaHSS Adapter', + pl: 'HomeMatic ReGaHSS Adapter', + uk: 'HomeMatic ReGaHSS Adapter', + 'zh-cn': 'HomeMatic ReGaHSS Adapter', + }, + description: { + en: 'These notifications represent news from your Homematic system.', + de: 'Diese Benachrichtigungen stellen Neuigkeiten von Ihrem Homematic System dar.', + ru: 'Эти уведомления представляют собой новости из вашей системы Homematic.', + pt: 'Estas notificações representam notícias do seu sistema Homematic.', + nl: 'Deze meldingen geven nieuws weer van je Homematic-systeem.', + fr: 'Ces notifications représentent des nouvelles de votre système Homematic.', + it: 'Queste notifiche rappresentano le novità del vostro sistema Homematic.', + es: 'Estas notificaciones representan noticias de su sistema Homematic.', + pl: 'Powiadomienia te przedstawiają wiadomości z systemu Homematic.', + uk: 'Ці сповіщення відображають новини з вашої системи Homematic.', + 'zh-cn': '这些通知代表来自 Homematic 系统的消息。', + }, + categories: [ + { + category: 'lowbat', + name: { + en: 'A device has a low battery level', + de: 'Ein Gerät hat einen niedrigen Batteriestand', + ru: 'В устройстве разряжен аккумулятор', + pt: 'Um dispositivo tem um nível de bateria baixo', + nl: 'De batterij van een apparaat is bijna leeg', + fr: "La batterie d'un appareil est faible", + it: 'Il livello della batteria di un dispositivo è basso', + es: 'Un dispositivo tiene un nivel bajo de batería', + pl: 'Urządzenie ma niski poziom naładowania baterii', + uk: 'Пристрій має низький рівень заряду акумулятора', + 'zh-cn': '设备电池电量不足', + }, + description: { + en: 'These devices have a low battery level.', + de: 'Diese Geräte haben einen niedrigen Batteriestand.', + ru: 'У этих устройств низкий уровень заряда батареи.', + pt: 'Estes dispositivos têm um nível de bateria baixo.', + nl: 'De batterij van deze apparaten is bijna leeg.', + fr: 'Ces appareils ont un niveau de batterie faible.', + it: 'Questi dispositivi hanno un livello di batteria basso.', + es: 'Estos dispositivos tienen un nivel de batería bajo.', + pl: 'Urządzenia te mają niski poziom naładowania baterii.', + uk: 'Ці пристрої мають низький рівень заряду батареї.', + 'zh-cn': '这些设备的电池电量不足。', + }, + regex: [], + limit: 1, + severity: 'notify', + }, + ], + }, + ], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If connected to CCU', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.ccuReachable', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If connected to CCU on IP layer', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.ccuRegaUp', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If rega is UP', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.lowbatDevices', + type: 'state', + common: { + role: 'state', + name: 'Devices which are running low on battery', + type: 'array', + read: true, + write: false, + def: '[]', + }, + native: {}, + }, + ], + objects: [ + { + _id: '_design/hm-rega', + type: 'design', + language: 'javascript', + views: { + variables: { + map: "function(doc) {\n if (doc._id.match(/^hm-rega\\.[0-9]+\\.[0-9,A-Z,a-z]+/) && (doc.native.TypeName === 'ALARMDP' || doc.native.TypeName === 'VARDP')) {\n emit(doc._id, doc);\n }\n}", + }, + programs: { + map: "function(doc) {\n if (doc._id.match(/^hm-rega\\.[0-9]+\\.[0-9,A-Z,a-z]+/) && (doc.native.TypeName === 'PROGRAM')) {\n emit(doc._id, doc);\n }\n}", + }, + }, + }, + ], + user: 'system.user.admin', + }, + 'system.adapter.telegram.0': { + _id: 'system.adapter.telegram.0', + type: 'instance', + common: { + name: 'telegram', + version: '3.9.0', + title: 'Telegram', + titleLang: { + en: 'Telegram', + de: 'Telegram', + ru: 'Telegram', + pt: 'Telegram', + nl: 'Telegram', + fr: 'Telegram', + it: 'Telegram', + es: 'Telegram', + pl: 'Telegram', + 'zh-cn': 'Telegram', + uk: 'Телеграма', + }, + desc: { + en: 'This adapter allows to send and receive telegram messages from ioBroker and to be a bot', + de: 'Adapter ermöglicht eine Kommunikation mit dem telegram app und ist selbst ein bot', + ru: 'Драйвер запускает Telegram бот, с которым можно общаться по App или через браузер', + pt: 'Este adaptador permite enviar e receber mensagens de telegramas de ioBroker e ser um bot', + nl: 'Met deze adapter kunt u telegramberichten van ioBroker verzenden en ontvangen en een bot zijn', + fr: "Cet adaptateur permet d'envoyer et de recevoir des messages de télégrammes d'ioBroker et d'être un bot", + it: 'Questo adattatore consente di inviare e ricevere messaggi di telegram da ioBroker e di essere un bot', + es: 'Este adaptador permite enviar y recibir mensajes de telegrama de ioBroker y ser un bot', + pl: 'Ten adapter umożliwia wysyłanie i odbieranie wiadomości telegramów z ioBroker i bycie botem', + 'zh-cn': '该适配器允许从ioBroker发送和接收电报消息并成为机器人', + uk: 'Цей адаптер дозволяє відправляти та отримувати телеграми від ioBroker і бути ботом', + }, + authors: [ + 'bluefox ', + 'apollon77 ', + 'Matthias Kleine ', + ], + license: 'MIT', + platform: 'Javascript/Node.js', + mode: 'daemon', + messagebox: true, + readme: 'https://github.com/iobroker-community-adapters/ioBroker.telegram/blob/master/README.md', + loglevel: 'info', + icon: 'telegram.png', + supportCustoms: true, + connectionType: 'cloud', + dataSource: 'poll', + compact: true, + tier: 1, + keywords: ['notification', 'telegram', 'message'], + restartSchedule: '4 5 * * *', + extIcon: + 'https://raw.githubusercontent.com/iobroker-community-adapters/ioBroker.telegram/master/admin/telegram.png', + type: 'messaging', + stopBeforeUpdate: true, + blockly: true, + adminUI: { + custom: 'json', + config: 'json', + }, + docs: { + en: ['docs/en/README.md'], + de: ['docs/de/README.md'], + }, + dependencies: [ + { + 'js-controller': '>=5.0.0', + }, + ], + globalDependencies: [ + { + admin: '>=6.1.6', + }, + ], + plugins: { + sentry: { + dsn: 'https://ae1b374ffb5d40cbabe9bff369520972@sentry.iobroker.net/38', + }, + }, + javascriptRules: { + i18n: true, + url: 'rules/customRuleBlocks.js', + name: 'ActionTelegram', + }, + installedFrom: 'iobroker.telegram@3.9.0', + installedVersion: '3.9.0', + enabled: true, + host: 'NanoPi-R5S', + supportedMessages: { + custom: true, + notifications: true, + }, + messages: [ + { + condition: { + operand: 'and', + rules: ['oldVersion<3.0.0', 'newVersion>=3.0.0'], + }, + title: { + en: 'Important notice!', + de: 'Wichtiger Hinweis!', + ru: 'Важное замечание!', + pt: 'Notícia importante!', + nl: 'Belangrijke mededeling!', + fr: 'Avis important!', + it: 'Avviso IMPORTANTE!', + es: 'Noticia importante!', + pl: 'Ważna uwaga!', + 'zh-cn': '重要通知!', + uk: 'Важливе повідомлення!', + }, + text: { + en: 'SOCKS-5 proxy support has been removed with release 3.0.0.', + de: 'SOCKS-5 Proxy-Unterstützung wurde mit Release 3.0.0 entfernt.', + ru: 'SOCKS-5 прокси поддержка была удалена с выпуском 3.0.0.', + pt: 'O suporte proxy SOCKS-5 foi removido com versão 3.0.0.', + nl: 'Quality over Quantity (QoQ) Releases Vertaling:.', + fr: 'Le support de proxy SOCKS-5 a été retiré avec la sortie 3.0.0.', + it: 'Il supporto proxy SOCKS-5 è stato rimosso con il rilascio 3.0.0.', + es: 'El soporte proxy SOCKS-5 ha sido eliminado con la versión 3.0.0.', + pl: 'Obsługa protokołu SOCKS-5 została usunięta z wydaniem 3.0.0.', + uk: 'SOCKS-5 Проксі-підтримка була вилучена з релізом 3.0.0.', + 'zh-cn': 'SOCKS-5传票后,释放了3 000人。.', + }, + link: 'https://github.com/iobroker-community-adapters/ioBroker.telegram#changelog', + level: 'warn', + linkText: { + en: 'Changelog', + de: 'Änderungsprotokoll', + ru: 'Список изменений', + pt: 'Registro de alterações', + nl: 'Wijzigingslog', + fr: 'Journal des modifications', + it: 'Registro delle modifiche', + es: 'registro de cambios', + pl: 'Dziennik zmian', + 'zh-cn': '变更日志', + uk: 'Журнал змін', + }, + buttons: ['agree', 'cancel'], + }, + ], + licenseInformation: { + license: 'MIT', + type: 'free', + link: 'https://github.com/iobroker-community-adapters/ioBroker.telegram/blob/master/LICENSE', + }, + }, + native: { + server: 'false', + pollingInterval: 300, + token: '$/aes-192-cbc:4685bf5d194c58b032fd2fa363a399b5:62b8b53aa91ef86e8a4fc044e7dc107db4553cfc53e721e1dbc2d4595e8e314b62b7d4e8d76a24f9245edcdef8f34111', + baseApiUrl: 'https://api.telegram.org', + password: '$/aes-192-cbc:103488b321a55c68e8bfe6c5fea90ac9:7b86d593a09b792d699adb61851a201a', + rememberUsers: true, + doNotAcceptNewUsers: false, + useUsername: false, + saveFiles: false, + saveFilesQuality: '0', + allowStates: true, + proxy: false, + proxyHost: '', + proxyPort: 1234, + proxyLogin: '', + proxyPassword: '', + restarted: '', + restarting: '', + keyboard: '?', + rooms: false, + storeRawRequest: false, + text2command: '', + url: '', + bind: '0.0.0.0', + port: 8443, + certPublic: '', + certPrivate: '', + certChained: '', + leEnabled: false, + leUpdate: false, + leCheckPort: 80, + saveFilesTo: 'filesystem', + answerTimeoutSec: 60, + }, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['token', 'password', 'proxyPassword', 'passwordRepeat'], + encryptedNative: ['token', 'password', 'proxyPassword'], + notifications: [], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: { + en: 'Meta storage for media files', + de: 'Meta-Speicher für Mediendateien', + ru: 'Мета-хранилище для медиафайлов', + pt: 'Meta armazenamento para arquivos de mídia', + nl: 'Meta-opslag voor mediabestanden', + fr: 'Stockage de métadonnées pour les fichiers multimédias', + it: 'Meta storage per file multimediali', + es: 'Meta almacenamiento para archivos multimedia', + pl: 'Meta do przechowywania plików medialnych', + uk: 'Мета зберігання для медіа файлів', + 'zh-cn': '媒体文件的元存储', + }, + type: 'meta.user', + }, + native: {}, + }, + { + _id: 'info', + type: 'channel', + common: { + name: { + en: 'Information', + de: 'Informationen', + ru: 'Информация', + pt: 'Informação', + nl: 'Informatie', + fr: 'Information', + it: 'Informazioni', + es: 'Información', + pl: 'Informacja', + uk: 'Інформація', + 'zh-cn': '信息', + }, + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + name: { + en: 'Connected to Telegram server', + de: 'Verbindung mit Telegram Server', + ru: 'Подключен к серверу Telegram', + pt: 'Conectado ao servidor Telegram', + nl: 'Verbinding met Telegram server', + fr: 'Connecté au serveur Telegram', + it: 'Collegato al server Telegram', + es: 'Conectado al servidor Telegram', + pl: 'Łączy się z serwerem Telegram', + uk: 'Підключення до сервера Telegram', + 'zh-cn': '电报服务器', + }, + type: 'boolean', + role: 'indicator.connected', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'communicate.request', + type: 'state', + common: { + name: { + en: 'Last received request', + de: 'Letzte empfangene Anfrage', + ru: 'Последний полученный запрос', + pt: 'Última solicitação recebida', + nl: 'Vertaling:', + fr: 'Dernière demande reçue', + it: 'Ultima richiesta', + es: 'Última solicitud recibida', + pl: 'Żądanie', + uk: 'Останній отримав запит', + 'zh-cn': '上次收到的请求', + }, + type: 'string', + role: 'text', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.requestRaw', + type: 'state', + common: { + name: { + en: 'Raw data of last received request', + de: 'Rohdaten der letzten eingegangenen Anfrage', + ru: 'Сырье последнего полученного запроса', + pt: 'Dados brutos do último pedido recebido', + nl: 'Rauw gegevens van het laatste verzoek', + fr: 'Données brutes de la dernière demande reçue', + it: "Dati grezzi dell'ultima richiesta ricevuta", + es: 'Datos brutos de la última solicitud recibida', + pl: 'Informacja o naniesionych żądaniach', + uk: 'Сирі дані останнього отриманого запиту', + 'zh-cn': '最后一次收到请求的数据', + }, + desc: { + en: 'Must be enabled in instance settings', + de: 'Muss in Instanz-Einstellungen aktiviert werden', + ru: 'Должна быть включена в настройках экземпляра', + pt: 'Deve ser ativado em configurações de instância', + nl: 'Moet ingeschakeld zijn in instantieinstellingen', + fr: "Doit être activé dans les paramètres d'instance", + it: 'Deve essere abilitato nelle impostazioni di istanza', + es: 'Debe ser habilitado en configuración de ejemplo', + pl: 'Musi być włączona na przykład ustawienia', + uk: 'Необхідно ввімкнути параметри екземпляра', + 'zh-cn': '在实例设置中必须启用', + }, + type: 'string', + role: 'json', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.requestChatId', + type: 'state', + common: { + name: { + en: 'Chat ID of last received request', + de: 'Chat ID der letzten empfangenen Anfrage', + ru: 'Chat ID последнего полученного запроса', + pt: 'ID de bate-papo do último pedido recebido', + nl: 'Chat ID van het laatste verzoek', + fr: 'Chat ID de la dernière demande reçue', + it: "Chat ID dell'ultima richiesta ricevuta", + es: 'Chat ID of last received request', + pl: 'Wywiad z ostatnią otrzymał żądanie', + uk: 'Чат ID останнього отриманого запиту', + 'zh-cn': '最后一次收到请求的国际组织', + }, + type: 'number', + role: 'value', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.requestMessageId', + type: 'state', + common: { + name: { + en: 'Message ID of last received request', + de: 'Nachrichten-ID der letzten empfangenen Anfrage', + ru: 'Сообщение ID последнего полученного запроса', + pt: 'ID de mensagem do último pedido recebido', + nl: 'Bericht van het laatste verzoek', + fr: 'Message ID de la dernière demande reçue', + it: "Messaggio ID dell'ultima richiesta ricevuta", + es: 'ID del mensaje de última solicitud recibida', + pl: 'Message ID of last otrzymało żądanie', + uk: 'Ідентифікатор повідомлення останнього отриманого запиту', + 'zh-cn': '上一次收到请求的邮件', + }, + type: 'number', + role: 'value', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.requestMessageThreadId', + type: 'state', + common: { + name: { + en: 'Thread ID of last received request', + de: 'Thread ID der letzten empfangenen Anfrage', + ru: 'Идентификатор последнего полученного запроса', + pt: 'ID de rosca do último pedido recebido', + nl: 'Thread ID van laatst ontvangen verzoek', + fr: "Numéro d'identification de la dernière demande reçue", + it: 'Thread ID di ultima richiesta ricevuta', + es: 'Thread ID of last received request', + pl: 'Identyfikator wątku ostatnio otrzymanego wniosku', + uk: 'Код нитки останнього отриманого запиту', + 'zh-cn': '上次收到请求的线索ID', + }, + type: 'number', + role: 'value', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.botSendChatId', + type: 'state', + common: { + name: { + en: 'Chat ID of last sent message by the bot', + de: 'Chat ID der letzten gesendeten Nachricht durch den Bot', + ru: 'Chat ID последнего отправленного сообщения ботом', + pt: 'ID de bate-papo da última mensagem enviada pelo bot', + nl: 'Chat ID van het laatste bericht van de bot', + fr: 'Chat ID du dernier message envoyé par le bot', + it: "Chat ID dell'ultimo messaggio inviato dal bot", + es: 'ID de chat del último mensaje enviado por el bot', + pl: 'Chat ID z ostatnią przesłaną przez bota', + uk: 'Чат ID останнього надісланого повідомлення від бота', + 'zh-cn': '黑客最后发出的讯息', + }, + type: 'string', + role: 'text', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.botSendMessageId', + type: 'state', + common: { + name: { + en: 'Message ID of last sent message by the bot', + de: 'Nachrichten-ID der letzten gesendeten Nachricht durch den Bot', + ru: 'Сообщение ID последнего отправленного сообщения ботом', + pt: 'ID de mensagem da última mensagem enviada pelo bot', + nl: 'Bericht ID van laatste verzonden bericht door de bot', + fr: 'Message ID du dernier message envoyé par le bot', + it: "Messaggio ID dell'ultimo messaggio inviato dal bot", + es: 'ID del mensaje enviado por el bot', + pl: 'Message ID z ostatniej wiadomości wysyłanej przez bota', + uk: 'Ідентифікатор повідомлення останнього надісланого повідомлення боту', + 'zh-cn': '黑客最后发出的讯', + }, + type: 'number', + role: 'value', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.botSendMessageThreadId', + type: 'state', + common: { + name: { + en: 'Thread ID of last sent message by the bot', + de: 'Thread ID der letzten gesendeten Nachricht durch den Bot', + ru: 'Thread ID последнего сообщения бота', + pt: 'ID de rosca da última mensagem enviada pelo bot', + nl: 'Thread ID van laatst verzonden bericht door de bot', + fr: 'Numéro de fil du dernier message envoyé par le bot', + it: "ID thread dell'ultimo messaggio inviato dal bot", + es: 'Thread ID of last sent message by the bot', + pl: 'Thread ID z ostatniej wiadomości wysyłanej przez bota', + uk: 'Нитка ID останнього надісланого повідомлення бо', + 'zh-cn': '机器人发送的最近消息的线索ID', + }, + type: 'number', + role: 'value', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.botSendRaw', + type: 'state', + common: { + name: { + en: 'Raw data of last sent message by the bot', + de: 'Rohdaten der letzten gesendeten Nachricht durch den Bot', + ru: 'Сырье последнего отправленного сообщения ботом', + pt: 'Dados brutos da última mensagem enviada pelo bot', + nl: 'Rauwe gegevens van het laatste bericht van de bot', + fr: 'Données brutes du dernier message envoyé par le bot', + it: "Dati grezzi dell'ultimo messaggio inviato dal bot", + es: 'Datos brutos del último mensaje enviado por el bot', + pl: 'Rezultaty z ostatniej wiadomości przez bota', + uk: 'Сирі дані останнього надісланого повідомлення від бота', + 'zh-cn': '黑白人最后发送的信息数据', + }, + type: 'string', + role: 'json', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.requestUserId', + type: 'state', + common: { + name: { + en: 'User ID of last received request', + de: 'Benutzer-ID der letzten empfangenen Anfrage', + ru: 'ID пользователя последнего полученного запроса', + pt: 'ID do usuário do último pedido recebido', + nl: 'User ID van het laatste verzoek', + fr: 'ID utilisateur de la dernière demande reçue', + it: "ID utente dell'ultima richiesta ricevuta", + es: 'ID de usuario de la última solicitud recibida', + pl: 'Użytkownik po raz ostatni otrzymał żądanie', + uk: 'Ідентифікатор користувача останнього отриманого запиту', + 'zh-cn': '上一次收到请求的用户', + }, + type: 'string', + role: 'text', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'communicate.response', + type: 'state', + common: { + name: { + en: 'Send text through Telegram with notification', + de: 'Text per Telegram senden mit Benachrichtigung', + ru: 'Отправить текст через телеграм с уведомлением', + pt: 'Enviar texto através do Telegram com notificação', + nl: 'Stuur een sms door Telegram met kennisgeving', + fr: 'Envoyer le texte par Telegram avec notification', + it: 'Invia testo tramite Telegram con notifica', + es: 'Enviar texto a través del Telegram con notificación', + pl: 'Tekst poprzez Telegram z powiadomieniem', + uk: 'Надіслати текст через Telegram повідомлення', + 'zh-cn': '通过电报复制件', + }, + type: 'string', + role: 'text', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'communicate.requestResponse', + type: 'state', + common: { + name: { + en: 'Respond to last received message in the same chat', + de: 'Antwort auf letzte empfangene Nachricht im gleichen Chat', + ru: 'Ответ на последнее полученное сообщение в том же чате', + pt: 'Responda à última mensagem recebida no mesmo chat', + nl: 'Antwoord op laatst ontvangen bericht in dezelfde chat', + fr: 'Répondre au dernier message reçu dans le même chat', + it: 'Rispondi a ultimo messaggio ricevuto nella stessa chat', + es: 'Responder al último mensaje recibido en el mismo chat', + pl: 'Respond to last received message in the same chat', + uk: 'Відповідність останнього отриманого повідомлення в одному чаті', + 'zh-cn': '在同一聊天中回复上次收到的消息', + }, + type: 'string', + role: 'text', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'communicate.responseSilent', + type: 'state', + common: { + name: { + en: 'Send text through Telegram silently', + de: 'Text per Telegram leise senden', + ru: 'Отправить текст через телеграм молча', + pt: 'Enviar texto através do Telegram silenciosamente', + nl: 'Stuur een sms door Telegram', + fr: 'Envoyer le texte par Telegram en silence', + it: 'Invia testo tramite Telegram silenziosamente', + es: 'Enviar texto a través del Telegram en silencio', + pl: 'Tekst poprzez Telegram milczeć', + uk: 'Надіслати текст через Телеграму мовчно', + 'zh-cn': '通过电线静态文本', + }, + type: 'string', + role: 'text', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'communicate.responseJson', + type: 'state', + common: { + name: { + en: 'Send text through Telegram with notification with JSON definition', + de: 'Text per Telegram mit Benachrichtigung mit JSON-Definition senden', + ru: 'Отправить текст через телеграм с уведомлением с определением JSON', + pt: 'Enviar texto através do Telegram com notificação com definição JSON', + nl: 'Stuur bericht door Telegram met definitie van JSON', + fr: 'Envoyer le texte par Telegram avec notification avec définition JSON', + it: 'Invia testo tramite Telegram con notifica con definizione JSON', + es: 'Enviar texto a través del Telegram con notificación con definición JSON', + pl: 'Tekst poprzez Telegram z notyfikacją z definicją JSON', + uk: 'Надіслати текст через Telegram повідомлення з визначенням JSON', + 'zh-cn': '通过电线传送的通知', + }, + type: 'string', + role: 'json', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'communicate.responseSilentJson', + type: 'state', + common: { + name: { + en: 'Send text through Telegram silently with JSON definition', + de: 'Text per Telegram still mit JSON-Definition senden', + ru: 'Отправить текст через телеграм молча с JSON определением', + pt: 'Enviar texto através do Telegram silenciosamente com a definição JSON', + nl: 'Stuur een sms door Telegram stilletjes met JSON definitie', + fr: 'Envoyer le texte par Telegram en silence avec la définition JSON', + it: 'Invia testo tramite Telegram in silenzio con la definizione JSON', + es: 'Enviar texto a través del Telegram en silencio con la definición JSON', + pl: 'Tekst minuskułowy milczy z definicją JSON', + uk: 'Відправте текст через Телеграму мовчно з визначенням JSON', + 'zh-cn': '通过与联合执行委员会的定义保持沉默的电报案文', + }, + type: 'string', + role: 'json', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'communicate.users', + type: 'state', + common: { + name: { + en: 'Users as JSON, which are constantly authenticated', + de: 'Benutzer als JSON, die ständig authentifiziert werden', + ru: 'Пользователи как JSON, которые постоянно аутентифицируются', + pt: 'Usuários como JSON, que são constantemente autenticados', + nl: 'Gebruikers als JSON, die constant geverifieerd worden', + fr: 'Utilisateurs comme JSON, qui sont constamment authentifiés', + it: 'Utenti come JSON, che sono costantemente autenticati', + es: 'Usuarios como JSON, que son constantemente autenticados', + pl: 'Użytkownicy JSON, którzy są stale autentyczni', + uk: 'Користувачі JSON, які постійно автентифікуються', + 'zh-cn': '经常核证的作为联合执行机构的用户', + }, + type: 'string', + role: 'json', + read: true, + write: false, + def: '{}', + }, + native: {}, + }, + { + _id: 'communicate.pathFile', + type: 'state', + common: { + name: { + en: 'Path to the last received file', + de: 'Pfad zur letzten empfangenen Datei', + ru: 'Путь к последнему полученному файлу', + pt: 'Caminho para o último arquivo recebido', + nl: 'Path naar het laatste bestand', + fr: 'Sentier du dernier fichier reçu', + it: "Percorso all'ultimo file ricevuto", + es: 'Send to the last received file', + pl: 'Path to the ostatni otrzymał plik plików', + uk: 'Шлях до останнього отриманого файлу', + 'zh-cn': '最后一次收到的档案', + }, + type: 'string', + role: 'text', + read: true, + write: false, + }, + native: {}, + }, + ], + objects: [], + from: 'system.host.NanoPi-R5S.cli', + user: 'system.user.admin', + ts: 1721775453455, + }, + 'system.adapter.iot.0': { + _id: 'system.adapter.iot.0', + type: 'instance', + common: { + name: 'iot', + version: '3.4.2', + title: 'IoT Assistants', + titleLang: { + en: 'IoT cloud connection', + de: 'Cloud IoT-Verbindung', + ru: 'Соединение Cloud IoT', + pt: 'Conexão Cloud IoT', + nl: 'Cloud IoT-verbinding', + fr: 'Connexion Cloud IoT', + it: 'Connessione Cloud IoT', + es: 'Conexión IoT en la nube', + pl: 'Połączenie Cloud IoT', + 'zh-cn': 'IoT云连接', + }, + desc: { + en: 'Connects your ioBroker server to the ioBroker IoT cloud', + de: 'Verbindet Ihren ioBroker-Server mit der ioBroker IoT-Cloud', + ru: 'Соединяет ваш сервер ioBroker с облаком ioBroker IoT', + pt: 'Conecta seu servidor ioBroker à nuvem IoT do ioBroker', + nl: 'Verbindt uw ioBroker-server met de ioBroker IoT-cloud', + fr: 'Connecte votre serveur ioBroker au cloud ioBroker IoT', + it: 'Collega il tuo server ioBroker al cloud IoT IoBroker', + es: 'Conecta su servidor ioBroker a la nube ioBroker IoT', + pl: 'Łączy twój serwer ioBroker z chmurą IoT ioBroker', + 'zh-cn': '连接你的ioBroker服务器的ioBroker IoT云', + }, + authors: ['bluefox '], + license: 'MIT', + platform: 'Javascript/Node.js', + mode: 'daemon', + loglevel: 'info', + readme: 'https://github.com/ioBroker/ioBroker.iot/blob/master/README.md', + icon: 'iot.png', + connectionType: 'cloud', + dataSource: 'push', + tier: 3, + keywords: ['web', 'Cloud', 'communication'], + enabled: true, + compact: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.iot/master/admin/iot.png', + type: 'communication', + messagebox: true, + stopBeforeUpdate: true, + materialize: true, + logTransporter: true, + dependencies: [ + { + 'js-controller': '>=3.3.22', + }, + ], + preserveSettings: 'smartName', + eraseOnUpload: true, + blockly: true, + osDependencies: { + linux: ['libcairo2-dev', 'libpango1.0-dev', 'libjpeg-dev', 'libgif-dev', 'librsvg2-dev'], + }, + plugins: { + sentry: { + dsn: 'https://20987eaf91ef49de821771499fdb4e1a@sentry.iobroker.net/40', + }, + }, + installedFrom: 'iobroker.iot@3.4.2', + installedVersion: '3.4.2', + host: 'NanoPi-R5S', + javascriptRules: { + i18n: true, + url: 'rules/customRuleBlocks.js', + name: 'ActionVisu', + }, + licenseInformation: { + type: 'free', + link: 'https://github.com/ioBroker/ioBroker.iot/blob/master/LICENSE', + license: 'MIT', + }, + globalDependencies: [ + { + admin: '>=4.0.1', + }, + ], + adminUI: { + config: 'materialize', + }, + }, + native: { + login: 'hunt@deko-lounge.de', + pass: '_W$\u0016W\\T\u0017h\u0001Q\u0000\u0001@', + language: '', + cloudUrl: 'a18wym7vjdl22g.iot.eu-west-1.amazonaws.com', + functionFirst: false, + concatWord: '', + responseOID: '', + restartOnDisconnect: false, + iftttKey: '', + replaces: '', + amazonAlexa: true, + amazonAlexaBlood: '', + amazonAlexaBloodShortAnswer: false, + googleHome: false, + yandexAlisa: false, + allowedServices: '', + text2command: '0', + nightscout: '', + nightscoutPass: 'myBlood', + noCommon: false, + debug: false, + remote: false, + remoteAdminInstance: '', + remoteWebInstance: '', + customKnownAlexaUsers: [], + addCustomKnownAlexaUserNameToText: false, + customKnownAlexaDevices: [], + addCustomKnownAlexaDeviceRoomToText: false, + amazonAlexaV3: false, + defaultToggle: true, + }, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['login', 'pass'], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If connected to cloud', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.ackTempPassword', + type: 'state', + common: { + role: 'indicator', + name: 'If user have read about temp password for iot', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.remoteTill', + type: 'state', + common: { + role: 'state', + name: 'Time till pro access is available', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.lastFunction', + type: 'state', + common: { + role: 'state', + name: 'Last controlled function', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.lastRoom', + type: 'state', + common: { + role: 'state', + name: 'Last controlled room', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.lastCommand', + type: 'state', + common: { + role: 'state', + name: 'Last command', + type: 'mixed', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.lastCommandObj', + type: 'state', + common: { + role: 'state', + name: 'Last command as object', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.lastResponse', + type: 'state', + common: { + role: 'state', + name: 'Last textual response', + type: 'string', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'smart.lastObjectID', + type: 'state', + common: { + role: 'state', + name: 'Last accessed object id', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.updates', + type: 'state', + common: { + role: 'state', + name: 'If updates of configuration is ready', + type: 'boolean', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.updates3', + type: 'state', + common: { + role: 'state', + name: 'If updates of V3 configuration is ready', + type: 'boolean', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.updatesGH', + type: 'state', + common: { + role: 'state', + name: 'If updates of google home configuration is ready', + type: 'boolean', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.updatesYA', + type: 'state', + common: { + role: 'state', + name: 'If updates of yandex alice configuration is ready', + type: 'boolean', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'smart.updatesResult', + type: 'state', + common: { + role: 'state', + name: 'Result for last devices update', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'services', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'certs', + type: 'channel', + common: { + expert: true, + name: 'Certificates', + }, + native: {}, + }, + { + _id: 'certs.id', + type: 'state', + common: { + expert: true, + role: 'state', + name: 'Certificate ID', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'certs.public', + type: 'state', + common: { + expert: true, + role: 'state', + name: 'Public key', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'certs.private', + type: 'state', + common: { + expert: true, + role: 'state', + name: 'Private key', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'certs.certificate', + type: 'state', + common: { + expert: true, + role: 'state', + name: 'Certificate', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'certs.urlKey', + type: 'state', + common: { + role: 'state', + name: 'URL Key', + desc: 'Used for access this instance via URL', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'certs.forceUserCreate', + type: 'state', + common: { + role: 'state', + name: 'Force user creation', + desc: 'Used to recreate the user and device anew', + def: false, + type: 'boolean', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'app', + type: 'channel', + common: { + expert: true, + name: 'Certificates', + }, + native: {}, + }, + { + _id: 'app.message', + type: 'state', + common: { + role: 'state', + name: 'Send message to app', + desc: "Could be just message or JSON object {message: 'text', title: 'title', expire: 60, priority: 1}", + type: 'string', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'app.title', + type: 'state', + common: { + role: 'state', + name: 'Title of message', + type: 'string', + read: true, + write: true, + }, + native: {}, + }, + { + _id: 'app.expire', + type: 'state', + common: { + role: 'state', + name: 'Expire time in seconds', + type: 'number', + unit: 'seconds', + read: true, + max: 86400, + min: 5, + write: true, + }, + native: {}, + }, + { + _id: 'app.priority', + type: 'state', + common: { + role: 'state', + name: 'Expire time in seconds', + type: 'string', + read: true, + states: { + 0: 'Normal', + 1: 'High', + }, + def: 'normal', + write: true, + }, + native: {}, + }, + ], + objects: [], + from: 'system.adapter.admin.0', + user: 'system.user.admin', + ts: 1727188170423, + }, + 'system.adapter.web.0': { + _id: 'system.adapter.web.0', + type: 'instance', + common: { + name: 'web', + version: '6.3.0', + title: 'WEB server', + titleLang: { + en: 'WEB server', + de: 'WEB-Server', + ru: 'Веб сервер', + pt: 'Servidor web', + nl: 'Web Server', + fr: 'Serveur Web', + it: 'Server web', + es: 'Servidor web', + pl: 'Serwer internetowy', + 'zh-cn': 'Web服务器', + uk: 'Веб-сервер', + }, + desc: { + en: 'Opens a webserver for other adapters', + de: "Stellt webserver für 'ioBroker Adapter' zur Verfügung", + ru: "Запускает веб сервер для 'ioBroker драйверов'", + pt: 'Abre um servidor web para outros adaptadores', + nl: 'Opent een webserver voor andere adapters', + fr: "Ouvre un serveur web pour d'autres adaptateurs", + it: 'Apre un server web per altri adattatori', + es: 'Abre un servidor web para otros adaptadores', + pl: 'Otwiera serwer internetowy dla innych kart', + 'zh-cn': '为其他适配器服务的web服务器', + uk: 'Відкриває веб-сервер для інших адаптерів', + }, + license: 'MIT', + mode: 'daemon', + platform: 'Javascript/Node.js', + loglevel: 'info', + icon: 'web.png', + readme: 'https://github.com/ioBroker/ioBroker.web/blob/master/README.md', + enabled: true, + materialize: true, + compact: true, + keywords: ['web', 'server', 'www', 'express'], + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.web/master/admin/web.png', + type: 'general', + stopBeforeUpdate: true, + eraseOnUpload: true, + webExtendable: true, + connectionType: 'local', + dataSource: 'push', + localLink: '%web_protocol%://%ip%:%web_port%/', + dependencies: [ + { + 'js-controller': '>=3.1.0', + }, + ], + globalDependencies: [ + { + admin: '>=5.1.0', + }, + ], + authors: [ + { + name: 'bluefox', + email: 'dogafox@gmail.com', + }, + ], + plugins: { + sentry: { + dsn: 'https://3acf24332d994549bfa3b86e06062c21@sentry.iobroker.net/16', + }, + }, + tier: 3, + installedFrom: 'iobroker.web@6.3.0', + installedVersion: '6.3.0', + host: 'NanoPi-R5S', + messagebox: true, + adminUI: { + config: 'materialize', + }, + licenseInformation: { + type: 'free', + link: 'https://github.com/ioBroker/ioBroker.web/blob/master/LICENSE', + }, + }, + native: { + port: 8082, + auth: false, + secure: false, + bind: '0.0.0.0', + cache: false, + socketio: '', + usePureWebSockets: false, + simpleapi: false, + defaultUser: 'admin', + ttl: 3600, + certPublic: '', + certPrivate: '', + certChained: '', + addUserName: false, + forceWebSockets: false, + compatibilityV2: true, + whiteListEnabled: false, + leEnabled: false, + leUpdate: false, + leCheckPort: 80, + loginBackgroundColor: '', + loginBackgroundImage: false, + basicAuth: false, + disableExtensions: false, + disableStates: false, + disableFilesObjects: false, + defaultRedirect: '', + staticAssetCacheMaxAge: 60, + language: '', + startDisabledExtensions: false, + showFolderIndex: false, + loadingBackgroundColor: '', + loadingHideLogo: false, + loadingBackgroundImage: false, + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1721775791191, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: 'user files and images for background image', + type: 'meta.user', + }, + native: {}, + }, + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'info.connected', + type: 'state', + common: { + role: 'state', + name: 'Info about connected socket clients', + type: 'string', + read: true, + write: false, + def: '', + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If web server started', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + ], + objects: [], + }, + 'system.adapter.cameras.0': { + _id: 'system.adapter.cameras.0', + type: 'instance', + common: { + name: 'cameras', + version: '2.1.2', + title: 'IP-Cameras', + titleLang: { + en: 'IP-Cameras', + de: 'IP-Kameras', + ru: 'IP-камера', + pt: 'Câmeras IP', + nl: "IP-camera's", + fr: 'Caméras IP', + it: 'Telecamere IP', + es: 'Cámaras IP', + pl: 'Kamery IP', + 'zh-cn': 'IP摄像机', + }, + desc: { + en: 'Connect IP-cameras to iobroker', + de: 'Schließen Sie IP-Kameras an iobroker an', + ru: 'Подключите IP-камеры к iobroker', + pt: 'Conecte câmeras IP ao iobroker', + nl: "Verbind IP-camera's met iobroker", + fr: 'Connectez des caméras IP à iobroker', + it: 'Collegare le telecamere IP a iobroker', + es: 'Conecte cámaras IP a iobroker', + pl: 'Podłącz kamery IP do iobroker', + 'zh-cn': '将IP摄像机连接到iobroker', + }, + authors: ['bluefox '], + keywords: ['ip-cam', 'web-cam', 'video'], + license: 'MIT', + platform: 'Javascript/Node.js', + icon: 'cameras.png', + enabled: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.cameras/master/admin/cameras.png', + readme: 'https://github.com/ioBroker/ioBroker.cameras/blob/master/README.md', + loglevel: 'debug', + webExtension: 'lib/web.js', + mode: 'daemon', + type: 'multimedia', + compact: true, + messagebox: true, + materialize: true, + subscribable: true, + eraseOnUpload: true, + stopBeforeUpdate: true, + dependencies: [ + { + 'js-controller': '>=3.1.4', + web: '>=2.0.0', + }, + ], + osDependencies: { + linux: ['ffmpeg'], + }, + connectionType: 'local', + dataSource: 'poll', + plugins: { + sentry: { + dsn: 'https://4559263b70ec40af801ccd777f5a79e6@sentry.iobroker.net/231', + }, + }, + installedFrom: 'iobroker.cameras@2.1.2', + installedVersion: '2.1.2', + host: 'NanoPi-R5S', + visWidgets: { + vis2CameraWidgets: { + i18n: 'component', + name: 'vis2CameraWidgets', + url: 'cameras/customWidgets.js', + color: '#508000', + label: 'cameras_set_label', + components: ['RtspCamera', 'SnapshotCamera'], + }, + }, + restartAdapters: ['vis-2'], + tier: 3, + licenseInformation: { + type: 'free', + license: 'MIT', + }, + adminUI: { + config: 'materialize', + }, + }, + native: { + bind: '127.0.0.1', + port: 8200, + key: '335254.263560', + webInstance: '*', + defaultTimeout: 2000, + defaultCacheTimeout: 100, + allowIPs: '', + ffmpegPath: '/usr/bin/ffmpeg', + tempPath: '', + dateFormat: 'LTS', + language: '', + cameras: [ + { + name: 'Terrasse', + type: 'reolinkE1', + url: 'https://raw.githubusercontent.com/ioBroker/ioBroker.admin/master/admin/admin.png', + id: 1687692075198, + ip: '192.168.178.68', + username: 'admin', + password: 'eL\u000f\u0012M[Z\u0004\u0005\u0007@', + timeout: 5000, + quality: 'high', + rtsp: true, + }, + ], + }, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: 'Cameras', + type: 'meta.user', + }, + native: {}, + }, + ], + objects: [], + from: 'system.host.NanoPi-R5S.cli', + user: 'system.user.admin', + ts: 1721744384947, + }, + 'system.adapter.hm-rpc.1': { + _id: 'system.adapter.hm-rpc.1', + type: 'instance', + common: { + name: 'hm-rpc', + title: 'HomeMatic IP', + desc: { + en: 'Connects HomeMatic Interface-Processes (BidCos-Services, Homegear and CUxD) via XML-RPC or BIN-RPC to ioBroker', + de: 'Verbindet HomeMatic Interface-Prozesse (BidCos-Services, Homegear und CUxD) via XML-RPC oder BIN-RPC mit ioBroker', + ru: 'Подключает HomeMatic интерфейсы (BidCos-сервисы, Homegear и CUxD) через XML-RPC или BIN-RPC к ioBroker', + pt: 'Conecta HomeMatic Interface-Processes (BidCos-Services, Homegear e CUxD) via XML-RPC ou BIN-RPC para ioBroker', + nl: 'Verbindt HomeMatic Interface-processen (BidCos-Services, Homegear en CUxD) via XML-RPC of BIN-RPC met ioBroker', + fr: "Connecte les processus d'interface HomeMatic (BidCos-Services, Homegear et CUxD) via XML-RPC ou BIN-RPC à ioBroker", + it: "Collega l'interfaccia HomeMatic: i processi (BidCos-Services, Homegear e CUxD) tramite XML-RPC o BIN-RPC su ioBroker", + es: 'Conecta los Procesos de Interfaz HomeMatic (BidCos-Services, Homegear y CUxD) a través de XML-RPC o BIN-RPC a ioBroker', + pl: 'Łączy procesy HomeMatic-Interface (BidCos-Services, Homegear i CUxD) za pośrednictwem XML-RPC lub BIN-RPC z ioBroker', + 'zh-cn': + '通过 XML-RPC 或 BIN-RPC 将 HomeMatic 接口进程(BidCos-Services、Homegear 和 CUxD)连接到 ioBroker', + uk: 'Підключає HomeMatic інтерфейси (BidCos-сервіси, Homegear і CUxD) через XML-RPC або BIN-RPC до ioBroker', + }, + version: '2.0.2', + authors: ['hobbyquaker ', 'Moritz Heusinger '], + license: 'MIT', + mode: 'daemon', + platform: 'Javascript/Node.js', + loglevel: 'info', + readme: 'https://github.com/ioBroker/ioBroker.hm-rpc/blob/master/README.md', + icon: 'homematic.png', + materialize: true, + compact: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.hm-rpc/master/admin/homematic.png', + keywords: [ + 'homematic', + 'bidcos', + 'eq3', + 'ELV', + 'CCU', + 'CCU1', + 'CCU2', + 'rpc', + 'xmlrpc', + 'homegear', + 'binrpc', + 'CUxD', + 'FS20', + 'FHT', + 'HMS', + 'EnOcean', + ], + type: 'iot-systems', + connectionType: 'local', + dataSource: 'push', + stopTimeout: 1000, + messagebox: true, + supportStopInstance: false, + dependencies: [ + { + 'js-controller': '>=5.0.19', + }, + ], + plugins: { + sentry: { + dsn: 'https://1bc0c96f48e44483b283bc5fc0ca91e2@sentry.iobroker.net/10', + pathWhitelist: [], + errorBlacklist: ['SyntaxError'], + }, + }, + adminUI: { + config: 'json', + }, + titleLang: { + en: 'HomeMatic RPC', + de: 'HomeMatic RPC', + ru: 'HomeMatic RPC', + pt: 'HomeMatic RPC', + nl: 'HomeMatic RPC', + fr: 'HomeMatic RPC', + it: 'HomeMatic RPC', + es: 'HomeMatic RPC', + pl: 'HomeMatic RPC', + 'zh-cn': 'HomeMatic RPC', + uk: 'HomeMatic RPC', + }, + tier: 2, + installedFrom: 'iobroker.hm-rpc@2.0.2', + installedVersion: '2.0.2', + enabled: true, + host: 'NanoPi-R5S', + supportedMessages: { + deviceManager: true, + }, + globalDependencies: [ + { + admin: '>=6.0.0', + }, + ], + licenseInformation: { + license: 'MIT', + type: 'free', + link: 'https://github.com/ioBroker/ioBroker.hm-rpc/blob/master/LICENSE', + }, + messages: [ + { + condition: { + operand: 'and', + rules: ['oldVersion<1.17.0', 'newVersion>=1.17.0'], + }, + title: { + en: 'Reenter your credentials for https', + de: 'Geben Sie erneut Ihre Anmeldeinformationen für https ein', + ru: 'Восстановить свои учетные данные для https', + pt: 'Insira suas credenciais para https', + nl: 'Uw referenties voor https opnieuw invoeren', + fr: 'Entrez de nouveau vos identifiants pour https', + it: 'Reinserire le credenziali per https', + es: 'Ingrese sus credenciales para https', + pl: 'Wprowadź swoje referencje do https', + uk: 'Відновити свої облікові дані за посиланням', + 'zh-cn': '重新输入您的 https 证书', + }, + text: { + en: 'The internal encryption method has been changed. Please enter your username and password in the instance configuration again.', + de: 'Die interne Verschlüsselungsmethode wurde geändert. Bitte geben Sie Ihren Benutzernamen und Ihr Passwort erneut in der Instanzkonfiguration ein.', + ru: 'Был изменен внутренний метод шифрования. Пожалуйста, введите ваше имя пользователя и пароль в конфигурации экземпляра снова.', + pt: 'O método de criptografia interna foi alterado. Digite seu nome de usuário e senha na configuração da instância novamente.', + nl: 'De interne coderingsmethode is gewijzigd. Voer uw gebruikersnaam en wachtwoord in de instantieconfiguratie opnieuw in.', + fr: "La méthode de chiffrement interne a été modifiée. Veuillez à nouveau saisir votre nom d'utilisateur et votre mot de passe dans la configuration de l'instance.", + it: "Il metodo di crittografia interna è stato modificato. Inserisci nuovamente il nome utente e la password nella configurazione dell'istanza.", + es: 'El método de cifrado interno ha sido cambiado. Ingrese su nombre de usuario y contraseña en la configuración de instancia de nuevo.', + pl: 'Wewnętrzna metoda szyfrowania została zmieniona. Proszę podać nazwę użytkownika i hasło w konfiguracji instancji ponownie.', + uk: "Змінено метод внутрішнього шифрування. Будь ласка, введіть ім'я користувача та пароль в налаштуваннях екземпляра знову.", + 'zh-cn': '内部加密方法已经改变. 请在实例配置中再次输入您的用户名和密码 .', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + }, + ], + }, + native: { + homematicAddress: '192.168.178.74', + adapterAddress: '192.168.178.73', + homematicPort: '2010', + callbackAddress: '', + port: '0', + type: 'xml', + daemon: 'HMIP', + checkInitInterval: '180', + reconnectInterval: '30', + forceReInit: false, + username: '', + password: '', + useHttps: false, + dontDelete: true, + }, + from: 'system.adapter.admin.0', + ts: 1727188165705, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['username', 'password'], + encryptedNative: ['username', 'password'], + notifications: [], + instanceObjects: [ + { + _id: 'updated', + type: 'state', + common: { + name: { + en: 'New devices added', + de: 'Neue Geräte hinzugefügt', + ru: 'Новые добавленные устройства', + pt: 'Novos dispositivos adicionados', + nl: 'Nieuwe apparaten toegevoegd', + fr: 'Nouveaux appareils ajoutés', + it: 'Nuovi dispositivi aggiunti', + es: 'Nuevos dispositivos añadidos', + pl: 'Dodano nowe urządzenia', + uk: 'Додані нові пристрої', + 'zh-cn': '新增设备', + }, + type: 'boolean', + read: true, + write: true, + }, + }, + { + _id: 'info', + type: 'channel', + common: { + name: { + en: 'Information', + de: 'Informationen', + ru: 'Информация', + pt: 'Informação', + nl: 'Informatie', + fr: 'Informations', + it: 'Informazioni', + es: 'Información', + pl: 'Informacje', + uk: 'Інформація', + 'zh-cn': '资料', + }, + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + name: { + en: 'Connected to CCU', + de: 'Verbindung mit CCU', + ru: 'Подключен к CCU', + pt: 'Conectado ao CCU', + nl: 'Verbonden met CCU', + fr: 'Connecté au CCU', + it: 'Collegato a CCU', + es: 'Conectado a la CCU', + pl: 'Połączone z CCU', + uk: 'Підключення до CCU', + 'zh-cn': '已连接到 CCU', + }, + type: 'boolean', + role: 'indicator.connected', + read: true, + write: false, + def: false, + }, + native: {}, + }, + ], + objects: [ + { + _id: '_design/hm-rpc', + type: 'design', + language: 'javascript', + views: { + listDevices: { + map: "function(doc) {\n if (doc._id.match(/^hm-rpc\\.[0-9]+\\.\\*?[A-Za-z0-9_-]+(\\.[0-9]+)?$/)) {\n emit(doc._id, {ADDRESS:(doc.native?doc.native.ADDRESS:''),VERSION:(doc.native?doc.native.VERSION:'')});\n }\n}", + }, + paramsetDescription: { + map: "function(doc) {\n if (doc._id.match(/^hm-rpc\\.meta/) && doc.meta.type === 'paramsetDescription') {\n emit(doc._id, doc);\n }\n}", + }, + }, + }, + ], + user: 'system.user.admin', + }, + 'system.adapter.history.0': { + _id: 'system.adapter.history.0', + type: 'instance', + common: { + name: 'history', + title: 'History', + titleLang: { + en: 'History', + de: 'History', + ru: 'History', + pt: 'History', + nl: 'History', + fr: 'History', + it: 'History', + es: 'History', + pl: 'History', + 'zh-cn': '历史', + }, + desc: { + en: 'Logging of the state history in files', + de: 'Protokollierung der Zustandsgeschichte in Dateien', + ru: 'Ведение истории событий в файлах', + pt: 'Registro do histórico de estado em arquivos', + nl: 'Logboekregistratie van de statusgeschiedenis in bestanden', + fr: "Consignation de l'historique des états dans les fichiers", + it: 'Registrazione della cronologia di stato nei file', + es: 'Registro del historial del estado en archivos', + pl: 'Rejestrowanie historii stanu w plikach', + 'zh-cn': '在文件中记录状态历史记录', + }, + version: '3.0.1', + mode: 'daemon', + platform: 'Javascript/Node.js', + loglevel: 'info', + messagebox: true, + subscribe: 'messagebox', + eraseOnUpload: true, + keywords: ['charts', 'history', 'logging', 'graphs', 'Graphen', 'data', 'archive'], + enabled: true, + compact: true, + preserveSettings: 'custom', + authors: ['bluefox ', 'hobbyquaker ', 'Apollon77 '], + license: 'MIT', + readme: 'https://github.com/ioBroker/ioBroker.history/blob/master/README.md', + icon: 'history.png', + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.history/master/admin/history.png', + type: 'storage', + supportCustoms: true, + getHistory: true, + dependencies: [ + { + 'js-controller': '>=3.3.0', + }, + ], + globalDependencies: [ + { + admin: '>=5.1.28', + }, + ], + supportStopInstance: 10000, + stopTimeout: 10000, + docs: { + en: ['docs/en/README.md'], + de: ['docs/de/README.md'], + }, + plugins: { + sentry: { + dsn: 'https://08fcc63117684cf3af4fa0e551857b5d@sentry.iobroker.net/35', + }, + }, + adminUI: { + config: 'json', + custom: 'json', + }, + connectionType: 'none', + dataSource: 'push', + tier: 1, + messages: [ + { + condition: { + operand: 'and', + rules: ['oldVersion<2.0.0', 'newVersion>=2.0.0'], + }, + title: { + en: 'Important notice!', + de: 'Wichtiger Hinweis!', + ru: 'Важное замечание!', + pt: 'Notícia importante!', + nl: 'Belangrijke mededeling!', + fr: 'Avis important!', + it: 'Avviso IMPORTANTE!', + es: 'Noticia importante!', + pl: 'Ważna uwaga!', + 'zh-cn': '重要通知!', + }, + text: { + en: 'This new version introduces several changes how values are logged because we fixed several issues and added new features. Please especially check the defined "debounce" and "block time" settings in your datapoints if values are not logged as expected and make sure the settings make sense. For more details please refer to the changelog and Readme.', + de: 'Diese neue Version führt mehrere Änderungen ein, wie Werte protokolliert werden, da wir mehrere Probleme behoben und neue Funktionen hinzugefügt haben. Bitte überprüfen Sie insbesondere die definierten „Entprellen“- und „Sperrzeit“-Einstellungen in Ihren Datenpunkten, wenn Werte nicht wie erwartet protokolliert werden, und stellen Sie sicher, dass die Einstellungen sinnvoll sind. Weitere Details finden Sie im Changelog und in der Readme.', + ru: 'В этой новой версии внесено несколько изменений в регистрацию значений, поскольку мы исправили несколько проблем и добавили новые функции. Пожалуйста, особенно проверьте определенные настройки «debounce» и «block time» в ваших точках данных, если значения не регистрируются должным образом, и убедитесь, что настройки имеют смысл. Для получения более подробной информации, пожалуйста, обратитесь к журналу изменений и Readme.', + pt: 'Esta nova versão apresenta várias alterações na forma como os valores são registrados, pois corrigimos vários problemas e adicionamos novos recursos. Verifique especialmente as configurações definidas de "debounce" e "block time" em seus pontos de dados se os valores não forem registrados conforme o esperado e verifique se as configurações fazem sentido. Para obter mais detalhes, consulte o log de alterações e o Leiame.', + nl: 'Deze nieuwe versie introduceert verschillende wijzigingen in de manier waarop waarden worden geregistreerd, omdat we verschillende problemen hebben opgelost en nieuwe functies hebben toegevoegd. Controleer vooral de gedefinieerde "debounce" en "block time" instellingen in uw datapunten als de waarden niet zijn vastgelegd zoals verwacht en zorg ervoor dat de instellingen kloppen. Raadpleeg de changelog en Readme voor meer informatie.', + fr: 'Cette nouvelle version introduit plusieurs changements dans la journalisation des valeurs car nous avons corrigé plusieurs problèmes et ajouté de nouvelles fonctionnalités. Veuillez vérifier en particulier les paramètres "anti-rebond" et "temps de blocage" définis dans vos points de données si les valeurs ne sont pas enregistrées comme prévu et assurez-vous que les paramètres ont un sens. Pour plus de détails, veuillez consulter le journal des modifications et le fichier Lisez-moi.', + it: 'Questa nuova versione introduce diverse modifiche al modo in cui i valori vengono registrati perché abbiamo risolto diversi problemi e aggiunto nuove funzionalità. Controllare in particolare le impostazioni definite "debounce" e "block time" nei propri datapoint se i valori non sono registrati come previsto e assicurarsi che le impostazioni abbiano un senso. Per maggiori dettagli, fare riferimento al log delle modifiche e al Leggimi.', + es: 'Esta nueva versión introduce varios cambios en la forma en que se registran los valores porque solucionamos varios problemas y agregamos nuevas funciones. Verifique especialmente la configuración definida de "antirrebote" y "tiempo de bloqueo" en sus puntos de datos si los valores no se registran como se esperaba y asegúrese de que la configuración tenga sentido. Para obtener más detalles, consulte el registro de cambios y el archivo Léame.', + pl: 'Ta nowa wersja wprowadza kilka zmian w sposobie rejestrowania wartości, ponieważ naprawiliśmy kilka problemów i dodaliśmy nowe funkcje. W szczególności sprawdź zdefiniowane ustawienia „odbicia” i „czasu blokowania” w punktach danych, jeśli wartości nie są rejestrowane zgodnie z oczekiwaniami i upewnij się, że ustawienia mają sens. Aby uzyskać więcej informacji, zapoznaj się z dziennikiem zmian i Readme.', + 'zh-cn': + '这个新版本引入了一些更改值的记录方式,因为我们修复了几个问题并添加了新功能。如果未按预期记录值,请特别检查数据点中定义的“去抖动”和“阻塞时间”设置,并确保设置有意义。有关更多详细信息,请参阅更改日志和自述文件。', + }, + link: 'https://github.com/ioBroker/ioBroker.history/blob/master/docs/en/README.md#settings', + level: 'warn', + linkText: { + en: 'Readme', + de: 'Liesmich', + ru: 'Прочти меня', + pt: 'Leia-me', + nl: 'Leesmij', + fr: 'Lisez-moi', + it: 'Leggimi', + es: 'Léame', + pl: 'Readme', + 'zh-cn': '自述文件', + }, + buttons: ['agree', 'cancel'], + }, + ], + installedFrom: 'iobroker.history@3.0.1', + installedVersion: '3.0.1', + host: 'NanoPi-R5S', + }, + native: { + maxLength: 960, + limit: 2000, + storeDir: '', + blockTime: 0, + debounceTime: 0, + retention: 31536000, + storeFrom: true, + storeAck: true, + changesRelogInterval: 0, + changesMinDelta: 0, + writeNulls: true, + disableSkippedValueLogging: false, + enableLogging: false, + round: '', + customRetentionDuration: 365, + }, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [], + objects: [], + from: 'system.host.NanoPi-R5S.cli', + user: 'system.user.admin', + ts: 1700991104369, + }, + 'system.adapter.cloud.0': { + _id: 'system.adapter.cloud.0', + type: 'instance', + common: { + name: 'cloud', + version: '5.0.1', + title: 'Cloud Adapter', + titleLang: { + en: 'Cloud connection', + de: 'Cloud-Verbindung', + ru: 'Облачное соединение', + pt: 'Conexão em nuvem', + nl: 'Cloud verbinding', + fr: 'Connexion au cloud', + it: 'Connessione cloud', + es: 'Conexión a la nube', + pl: 'Połączenie w chmurze', + 'zh-cn': '云连接', + }, + desc: { + en: 'Connects your ioBroker server to the ioBroker cloud', + de: 'Verbindet Ihren ioBroker-Server mit der ioBroker-Cloud', + ru: 'Подключает сервер ioBroker к облаку ioBroker', + pt: 'Conecta seu servidor ioBroker à nuvem ioBroker', + nl: 'Verbindt uw ioBroker-server met de ioBroker-cloud', + fr: 'Connecte votre serveur ioBroker au cloud ioBroker', + it: 'Collega il tuo server ioBroker al cloud ioBroker', + es: 'Conecta tu ioBroker servidor a la ioBroker en la nube', + pl: 'Łączy serwer ioBroker na ioBroker chmura', + 'zh-cn': '连接你的ioBroker服务器的ioBroker云', + }, + authors: ['bluefox '], + license: 'MIT', + platform: 'Javascript/Node.js', + mode: 'daemon', + loglevel: 'info', + readme: 'https://github.com/ioBroker/ioBroker.cloud/blob/master/README.md', + icon: 'cloud.png', + keywords: ['web', 'Cloud', 'communication'], + compact: true, + enabled: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.cloud/master/admin/cloud.png', + type: 'communication', + messagebox: true, + stopBeforeUpdate: true, + materialize: true, + dependencies: [ + { + 'js-controller': '>=3.1.3', + }, + ], + preserveSettings: 'smartName', + blockly: true, + logTransporter: true, + adminUI: { + config: 'json', + }, + connectionType: 'cloud', + dataSource: 'push', + plugins: { + sentry: { + dsn: 'https://4e98835e3b074c49a3e31d51a46801a2@sentry.iobroker.net/33', + }, + }, + installedFrom: 'iobroker.cloud@5.0.1', + installedVersion: '5.0.1', + logLevel: 'info', + host: 'NanoPi-R5S', + licenseInformation: { + type: 'free', + link: 'https://github.com/ioBroker/ioBroker.cloud/blob/master/LICENSE', + }, + tier: 2, + }, + native: { + language: '', + login: 'hunt@deko-lounge.de', + pass: '$/aes-192-cbc:4d2e70f69bc6d0035e46be81afd1f63a:3bb91ad4dc337b2a8ab2c496169086e9', + server: 'iobroker.pro', + apikey: '@pro_hunt@deko-lounge.de_c8c8d760-06ef-11ee-a7c8-c3f272fd8e2f', + instance: 'web.0', + cloudUrl: 'https://iobroker.net:10555', + connectionTimeout: 10000, + allowSelfSignedCertificate: true, + functionFirst: false, + concatWord: '', + responseOID: '', + restartOnDisconnect: false, + pingTimeout: 5000, + iftttKey: '', + replaces: '', + allowedServices: '', + text2command: '0', + allowAdmin: '', + lovelace: '', + noCommon: false, + useCredentials: true, + }, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['login', 'pass', 'apikey'], + encryptedNative: ['pass'], + notifications: [], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If connected to cloud', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.userOnCloud', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If user is connected over cloud', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.remoteTill', + type: 'state', + common: { + role: 'state', + name: 'Time till pro access is available', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'services', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + ], + objects: [], + from: 'system.host.NanoPi-R5S.cli', + user: 'system.user.admin', + ts: 1721744426930, + }, + 'system.adapter.echarts.0': { + _id: 'system.adapter.echarts.0', + type: 'instance', + common: { + name: 'echarts', + version: '1.9.2', + title: 'eCharts Adapter', + titleLang: { + en: 'E-Charts', + de: 'E-Charts', + ru: 'E-диаграмма', + pt: 'E-Charts', + nl: 'E-Grafieken', + fr: 'E-Charts', + it: 'E-Charts', + es: 'E-Charts', + pl: 'Wykresy elektroniczne', + 'zh-cn': '电子图', + uk: 'E-діаграма', + }, + desc: { + en: 'Build useful charts in ioBroker', + de: 'Erstellen Sie nützliche Diagramme in ioBroker', + ru: 'Создавайте полезные графики в ioBroker', + pt: 'Crie gráficos úteis no ioBroker', + nl: 'Bouw handige grafieken in ioBroker', + fr: 'Construire des graphiques utiles dans ioBroker', + it: 'Crea grafici utili in ioBroker', + es: 'Cree gráficos útiles en ioBroker', + pl: 'Twórz przydatne wykresy w ioBroker', + 'zh-cn': '在ioBroker中建立有用的图表', + uk: 'Створюйте корисні діаграми в ioBroker', + }, + authors: ['bluefox '], + keywords: ['charts', 'diagram'], + adminTab: { + singleton: true, + name: { + ru: 'Графики', + en: 'Charts', + de: 'Diagramme', + pt: 'Gráficos', + nl: 'Grafieken', + fr: 'Graphiques', + it: 'Grafici', + es: 'Gráficos', + pl: 'Wykresy', + uk: 'Графіки', + 'zh-cn': '图表', + }, + }, + license: 'Apache-2.0', + platform: 'Javascript/Node.js', + connectionType: 'local', + dataSource: 'push', + icon: 'echarts.png', + messagebox: true, + eraseOnUpload: true, + enabled: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.echarts/master/admin/echarts.png', + readme: 'https://github.com/ioBroker/ioBroker.echarts/blob/master/README.md', + loglevel: 'info', + noConfig: true, + singleton: true, + type: 'visualization', + mode: 'daemon', + compact: true, + installedFrom: 'iobroker.echarts@1.9.2', + installedVersion: '1.9.2', + logLevel: 'info', + host: 'NanoPi-R5S', + visWidgets: { + echarts: { + i18n: 'component', + name: 'echarts', + url: 'echarts/customWidgets.js', + components: ['Echarts'], + }, + }, + restartAdapters: ['vis-2'], + adminUI: { + config: 'none', + tab: 'html', + }, + nogit: true, + tier: 3, + licenseInformation: { + license: 'Apache-2.0', + type: 'free', + }, + }, + native: {}, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: 'user files and images for echarts', + type: 'meta.user', + }, + native: {}, + }, + ], + objects: [ + { + _id: '_design/chart', + type: 'design', + language: 'javascript', + views: { + chart: { + map: "function(doc) { if (doc.type === 'chart') emit(doc._id, doc); }", + }, + }, + }, + ], + from: 'system.host.NanoPi-R5S.cli', + user: 'system.user.admin', + ts: 1726357247265, + }, + 'system.adapter.vis.0': { + _id: 'system.adapter.vis.0', + type: 'instance', + common: { + name: 'vis', + version: '1.5.6', + title: 'Interface für Tablets und Desktops', + titleLang: { + en: 'Visualisation', + de: 'Visualisierung', + ru: 'Визуализация', + pt: 'Visualização', + nl: 'Visualisatie', + fr: 'Visualisation', + it: 'Visualizzazione', + es: 'Visualización', + pl: 'Wizualizacja', + 'zh-cn': '可视化', + uk: 'Візуалізація', + }, + desc: { + en: 'Graphical user interface for iobroker', + de: 'Grafische Benutzeroberfläche für iobroker', + ru: 'Графический пользовательский интерфейс для iobroker', + pt: 'Interface gráfica do usuário para iobroker', + nl: 'Grafische gebruikersinterface voor iobroker', + fr: 'Interface utilisateur graphique pour iobroker', + it: 'Interfaccia utente grafica per iobroker', + es: 'Interfaz gráfica de usuario para iobroker', + pl: 'Graficzny interfejs użytkownika dla iobroker', + 'zh-cn': 'iobroker的图形化用户界面', + uk: 'Графічний інтерфейс користувача для iobroker', + }, + platform: 'Javascript/Node.js', + loglevel: 'info', + icon: 'vis.png', + enabled: true, + mode: 'once', + extIcon: 'https://raw.githubusercontent.com/iobroker/iobroker.vis/master/admin/vis.png', + keywords: ['DashUI', 'GUI', 'graphical', 'scada'], + readme: 'https://github.com/iobroker/iobroker.vis/blob/master/README.md', + authors: ['bluefox '], + localLinks: { + _default: '%web_protocol%://%ip%:%web_port%/vis/edit.html', + }, + license: 'MIT', + dependencies: [ + { + web: '>=3.0.12', + }, + { + 'js-controller': '>=2.0.0', + }, + ], + restartAdapters: ['vis'], + serviceStates: 'lib/states.js', + singleton: true, + type: 'visualization', + connectionType: 'local', + dataSource: 'push', + tier: 3, + noConfig: true, + adminUI: { + config: 'none', + }, + compact: true, + materialize: true, + welcomeScreen: { + link: 'vis/index.html', + name: 'vis runtime', + img: 'vis/img/favicon.png', + color: '#ffe9c8', + order: 0, + }, + welcomeScreenPro: { + link: 'vis/edit.html', + name: 'vis editor', + img: 'vis/img/faviconEdit.png', + color: '#c8ffe1', + order: 1, + }, + installedFrom: 'iobroker.vis@1.5.6', + installedVersion: '1.5.6', + logLevel: 'info', + host: 'NanoPi-R5S', + eraseOnUpload: false, + licenseInformation: { + type: 'free', + }, + }, + native: { + defaultFileMode: 1604, + license: '', + useLicenseManager: 0, + }, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: 'user files and images for vis', + type: 'meta.user', + }, + native: {}, + }, + { + _id: 'control', + type: 'channel', + common: { + name: 'Control vis', + }, + native: {}, + }, + { + _id: 'control.instance', + type: 'state', + common: { + name: 'Control vis', + type: 'string', + desc: "Write here browser instance ID to control or 'FFFFFFFF' to control all instances", + }, + native: {}, + }, + { + _id: 'control.command', + type: 'state', + common: { + name: 'Command for vis', + type: 'string', + desc: "Writing this variable act as the trigger. Instance and data must be preset before 'command' will be written. 'changedView' will be signalled too", + states: { + alert: 'alert', + changeView: 'changeView', + refresh: 'refresh', + reload: 'reload', + dialog: 'dialog', + popup: 'popup', + playSound: 'playSound', + changedView: 'changedView', + tts: 'tts', + }, + }, + native: {}, + }, + { + _id: 'control.data', + type: 'state', + common: { + name: 'Data for control vis', + type: 'string', + desc: 'Used for: alert, changeView, dialog, popup, playSound, changedView', + }, + native: {}, + }, + ], + objects: [], + from: 'system.host.NanoPi-R5S.cli', + user: 'system.user.admin', + ts: 1716815073632, + }, + 'system.adapter.link.0': { + _id: 'system.adapter.link.0', + type: 'instance', + common: { + name: 'link', + title: 'Link VPN', + titleLang: { + en: 'Link VPN', + }, + desc: { + en: 'Create VPN connection via ioBroker', + de: 'Erstellen Sie eine VPN-Verbindung über ioBroker', + ru: 'Создание VPN-соединения через ioBroker', + pt: 'Crie uma conexão VPN via ioBroker', + nl: 'Maak een VPN-verbinding via ioBroker', + fr: 'Créer une connexion VPN via ioBroker', + it: 'Crea una connessione VPN tramite ioBroker', + es: 'Crear una conexión VPN a través de ioBroker', + }, + version: '0.5.12', + mode: 'daemon', + platform: 'Javascript/Node.js', + loglevel: 'info', + keywords: ['vpn', 'link', 'remote access'], + connectionType: 'cloud', + dataSource: 'push', + main: 'main.js', + enabled: true, + authors: ['gh-god', 'Bluefox '], + restartSchedule: '0 4 * * *', + compact: true, + materialize: true, + license: 'CC-BY-NC-4.0', + readme: 'https://github.com/ioBroker/ioBroker.link/blob/master/README.md', + icon: 'link.png', + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.link/master/admin/link.png', + type: 'communication', + dependencies: [ + { + 'js-controller': '>=1.2.3', + }, + ], + stopTimeout: 10000, + installedFrom: 'iobroker.link@0.5.12', + installedVersion: '0.5.12', + host: 'NanoPi-R5S', + adminUI: { + config: 'materialize', + }, + }, + native: { + name: 'Talstrasse', + accessServerURI: 'https://iobroker.link', + accessServerPollInterval: '10', + telegramAsk: false, + telegramInstance: '', + allowedUsers: [ + { + enabled: true, + user: 'odroid', + once: '', + }, + { + enabled: true, + user: 'dogafox@gmail.com', + once: '', + }, + ], + proxyURI: '', + devices: [ + { + enabled: true, + name: 'ioBroker Admin', + host: 'localhost', + port: '8081', + protocol: 'TCP', + }, + { + enabled: true, + name: 'ioBroker Web', + host: 'localhost', + port: '8082', + protocol: 'TCP', + }, + { + enabled: true, + name: 'Homematic', + host: '192.168.178.74', + port: '80', + protocol: 'TCP', + }, + ], + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1686475981661, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + role: 'indicator.connection', + name: 'Connected to cloud', + type: 'boolean', + read: true, + write: false, + }, + native: {}, + }, + { + _id: 'info.status', + type: 'state', + common: { + role: 'text', + name: 'Client status', + desc: 'This text will be send to cloud to indicate the client overall status. Empty is ok. Some text describes error.', + type: 'string', + read: true, + write: false, + }, + native: {}, + }, + ], + objects: [], + user: 'system.user.admin', + }, + 'system.adapter.fb-checkpresence.0': { + _id: 'system.adapter.fb-checkpresence.0', + type: 'instance', + common: { + name: 'fb-checkpresence', + version: '1.2.5', + titleLang: { + en: 'Fritzbox CheckPresence', + de: 'Fritzbox CheckPresence', + ru: 'Fritzbox CheckPresence', + pt: 'Fritzbox CheckPresence', + nl: 'Fritzbox CheckPresence', + fr: 'Fritzbox CheckPresence', + it: 'Fritzbox CheckPresence', + es: 'Fritzbox CheckPresence', + pl: 'Fritzbox CheckPresence', + 'zh-cn': 'Fritzbox CheckPresence', + uk: 'Fritzbox CheckPresence', + }, + desc: { + en: 'The adapter checks the presence of family members over the fritzbox. You must fill in the name of the family member and the mac-address of the used device. The comment is optional and you can enable or disable the family member. The datapoint based on the member name.', + de: 'Der Adapter prüft die Anwesenheit von Familienmitgliedern über die Fritzbox. ', + ru: 'Адаптер проверяет присутствие членов семьи через fritzbox. ', + pt: 'O adaptador verifica a presença de membros da família sobre o fritzbox. ', + nl: 'De adapter controleert de aanwezigheid van familieleden via de fritzbox. ', + fr: "L'adaptateur vérifie la présence de membres de la famille sur la fritzbox. ", + it: "L'adattatore controlla la presenza dei membri della famiglia sul fritzbox. ", + es: 'El adaptador comprueba la presencia de miembros de la familia sobre el fritzbox. ', + pl: 'Adapter sprawdza obecność członków rodziny na fritzbox. ', + 'zh-cn': '适配器通过fritzbox检查家庭成员的存在。', + uk: "Адаптер перевіряє присутність членів сім'ї над fritzbox. Необхідно вказати ім'я члена сім'ї та mac-адресу використовуваного пристрою. Коментар необов’язковий, і ви можете ввімкнути або вимкнути члена сім’ї. Точка даних на основі імені члена.", + }, + authors: ['Achim Fürhoff '], + keywords: ['presence', 'family', 'tr064', 'fritz.box', 'fritzbox'], + license: 'MIT', + platform: 'Javascript/Node.js', + main: 'main.js', + icon: 'fb-checkpresence.png', + enabled: false, + extIcon: + 'https://raw.githubusercontent.com/afuerhoff/ioBroker.fb-checkpresence/master/admin/fb-checkpresence.png', + readme: 'https://github.com/afuerhoff/ioBroker.fb-checkpresence/blob/master/README.md', + loglevel: 'info', + mode: 'daemon', + type: 'infrastructure', + connectionType: 'local', + dataSource: 'poll', + compact: true, + materialize: true, + stopBeforeUpdate: true, + stopTimeout: 1000, + messagebox: true, + dependencies: [ + { + 'js-controller': '>=5.0.19', + }, + ], + installedFrom: 'iobroker.fb-checkpresence@1.2.5', + installedVersion: '1.2.5', + host: 'NanoPi-R5S', + licenseInformation: { + type: 'free', + link: 'https://github.com/afuerhoff/ioBroker.fb-checkpresence/blob/master/LICENSE', + license: 'MIT', + }, + tier: 3, + adminUI: { + config: 'materialize', + }, + }, + native: { + familymembers: [], + whitelist: [], + ipaddress: 'fritz.box', + ssl: true, + interval: 20, + interval_seconds: true, + intervalFamily: 60, + delay: 15, + compatibility: true, + history: 'history.0', + dateformat: 'yyyy.mm.dd HH:MM:ss', + fbdevices: true, + meshinfo: false, + syncfbdevices: false, + guestinfo: true, + qrcode: false, + qrcodecolor: 'black', + extip: true, + username: 'iobroker', + password: '$/aes-192-cbc:6f2525d019e0a88bdfc271fe465fbd65:007ef5fab30bfce8c26dd5313d2f6359', + enableWl: true, + newfilter: false, + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1726881008599, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['password'], + encryptedNative: ['password'], + notifications: [], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + ], + objects: [], + user: 'system.user.admin', + }, + 'system.adapter.sayit.0': { + _id: 'system.adapter.sayit.0', + type: 'instance', + common: { + name: 'sayit', + version: '5.0.0', + title: 'Text to speech', + titleLang: { + en: 'Text to speech', + de: 'Text zu Sprache', + ru: 'Текст в речь (Text to speech)', + pt: 'Texto para fala (Text to speech)', + nl: 'Tekst naar spraak (Text to speech)', + fr: 'Texte pour parler (Text to speech)', + it: 'Sintesi vocale (Text to speech)', + es: 'Texto a voz (Text to speech)', + pl: 'Tekst na mowę (Text to speech)', + 'zh-cn': '文字到语音', + uk: 'Перетворення тексту на мовлення', + }, + desc: { + en: 'Text to speech in a cloud or local. Runs on windows, linux and OSX. It can play mp3/wav too.', + de: 'Text to speech in Cloud oder lokal für windows, linux und OSX. Mp3 und Wav können auch abgespielt werden.', + ru: 'Синтезатор речи локально или в облаке работает под windows, linux и OSX. Mp3 и Wav можно тоже проигрывать.', + pt: 'Texto para fala em uma nuvem ou local. Funciona no windows, linux e OSX. Pode reproduzir mp3 / wav também.', + nl: 'Tekst naar spraak in een cloud of lokaal. Werkt op Windows, Linux en OSX. Het kan ook mp3 / wav spelen.', + fr: 'Text to speech dans un nuage ou local. Fonctionne sur Windows, Linux et OSX. Il peut aussi jouer au format mp3 / wav.', + it: 'Sintesi vocale in un cloud o locale. Funziona su Windows, Linux e OSX. Può riprodurre anche mp3 / wav.', + es: 'Texto a voz en una nube o local. Se ejecuta en Windows, Linux y OSX. Puede reproducir mp3 / wav también.', + pl: 'Tekst na mowę w chmurze lub lokalnie. Działa w systemie Windows, Linux i OSX. Może również odtwarzać mp3 / wav.', + 'zh-cn': '文字到语音在云端或局部的。 运行在windows、linux和OS x. 它可以发挥的mp3/声。', + uk: 'Перетворення тексту в мовлення в хмарі або локально. Працює на Windows, Linux і OSX. Він також може відтворювати mp3/wav.', + }, + authors: ['bluefox '], + license: 'MIT', + platform: 'Javascript/Node.js', + mode: 'daemon', + readme: 'https://github.com/ioBroker/ioBroker.sayit/blob/master/README.md', + loglevel: 'info', + messagebox: true, + supportStopInstance: true, + stopBeforeUpdate: true, + icon: 'sayit.png', + materialize: true, + adminUI: { + config: 'json', + }, + connectionType: 'cloud', + dataSource: 'push', + tier: 3, + enabled: false, + compact: true, + keywords: ['TTS', 'voice', 'speech'], + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.sayit/master/admin/sayit.png', + type: 'multimedia', + blockly: true, + plugins: { + sentry: { + dsn: 'https://e814e4a55077465b9ac16ac3062dee10@sentry.iobroker.net/85', + }, + }, + dependencies: [ + { + 'js-controller': '>=5.0.19', + }, + ], + installedFrom: 'iobroker.sayit@5.0.0', + installedVersion: '5.0.0', + host: 'NanoPi-R5S', + licenseInformation: { + license: 'MIT', + type: 'free', + }, + globalDependencies: [ + { + admin: '>=7.0.13', + }, + ], + }, + native: { + type: 'system', + cache: true, + cacheDir: '../../cache/', + engine: '', + sonosDevice: '', + heosDevice: '', + mpdDevice: '', + googleHomeServer: '', + chromecastDevice: '', + mp24Server: '', + ftpPort: 0, + ftpUser: '', + ftpPass: '', + browserInstance: 'FFFFFFFF', + webServer: '', + announce: '', + annoTimeout: 15, + annoDuration: 0, + annoVolume: '70', + cloudAppKey: '', + cloudInstance: '', + yandexEffectVoice: '', + yandexKey: '', + yandexEmotion: '', + yandexFolderID: '', + awsAccessKey: '', + awsSecretKey: '', + awsRegion: '', + convertedV1toV2: true, + systemCommand: '', + systemPlayer: '', + browserVis: '', + webInstance: '', + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1721775300161, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: 'User files for SayIt', + type: 'meta.user', + }, + native: {}, + }, + { + _id: 'tts', + type: 'channel', + common: { + name: 'Google text to speech', + role: 'media.tts', + }, + native: {}, + }, + { + _id: 'tts.userfiles', + type: 'meta', + common: { + name: 'Gong files', + role: 'meta.user', + }, + native: {}, + }, + { + _id: 'tts.volume', + type: 'state', + common: { + role: 'level.volume', + name: 'TTS Volume', + min: 0, + max: 100, + def: 70, + type: 'number', + read: true, + write: true, + desc: 'System volume or remote device volume', + }, + native: {}, + }, + { + _id: 'tts.text', + type: 'state', + common: { + role: 'media.tts.text', + name: 'Text to speech', + type: 'string', + read: true, + write: true, + desc: 'This text will be converted to speech', + }, + native: {}, + }, + { + _id: 'tts.clearQueue', + type: 'state', + common: { + role: 'button', + name: 'Clear queued texts', + type: 'boolean', + read: false, + write: true, + desc: 'If you need to say something immediately and the queue is full, set it to true before sending the new task', + }, + native: {}, + }, + { + _id: 'tts.cachetext', + type: 'state', + common: { + role: 'media.tts.cachetext', + name: 'Text to cache', + type: 'string', + read: true, + write: true, + desc: 'This text will be cached on disk to play it later', + }, + native: {}, + }, + { + _id: 'tts.playing', + type: 'state', + common: { + role: 'media.tts.text', + name: 'Is now speaking', + type: 'boolean', + read: true, + write: false, + desc: 'Is true while speaking', + }, + native: {}, + }, + ], + objects: [], + user: 'system.user.admin', + }, + 'system.adapter.alexa2.0': { + _id: 'system.adapter.alexa2.0', + type: 'instance', + common: { + name: 'alexa2', + version: '3.26.5', + blockedVersions: ['~3.14.0', '~3.15.0', '~3.16.0', '3.17.0', '3.17.1', '3.17.2', '3.17.3'], + title: 'Alexa2 (Amazon Echo)', + titleLang: { + en: 'Alexa2 (Amazon Echo)', + de: 'Alexa2 (Amazon Echo)', + ru: 'Alexa2 (Amazon Echo)', + pt: 'Alexa2 (Amazon Echo)', + nl: 'Alexa2 (Amazon Echo)', + fr: 'Alexa2 (Amazon Echo)', + it: 'Alexa2 (Amazon Echo)', + es: 'Alexa2 (eco de Amazon)', + pl: 'Alexa2 (Amazon Echo)', + 'zh-cn': 'Alexa2(Amazon回声)', + uk: 'Alexa2 (Amazon Echo)', + }, + desc: { + en: 'Remote control for Alexa (Amazon Echo)', + de: 'Steuerung von Alexa (Amazon Echo)', + ru: 'Управление Alexa (Amazon Echo)', + pt: 'Controle remoto para Alexa (Amazon Echo)', + nl: 'Afstandsbediening voor Alexa (Amazon Echo)', + fr: 'Télécommande pour Alexa (Amazon Echo)', + it: 'Telecomando per Alexa (Amazon Echo)', + es: 'Control remoto para Alexa (Amazon Echo)', + pl: 'Pilot do Alexa (Amazon Echo)', + 'zh-cn': 'Alexa(Amazon Echo)的遥控器', + uk: 'Пульт дистанційного керування для Alexa (Amazon Echo)', + }, + platform: 'Javascript/Node.js', + keywords: ['alexa', 'amazon', 'amazon echo', 'echo dot', 'echo show'], + authors: ['Apollon77 '], + mode: 'daemon', + icon: 'alexa.png', + materialize: true, + extIcon: 'https://raw.githubusercontent.com/Apollon77/ioBroker.alexa2/master/admin/alexa.png', + readme: 'https://github.com/Apollon77/ioBroker.alexa2/blob/master/README.md', + loglevel: 'debug', + type: 'iot-systems', + enabled: false, + messagebox: true, + license: 'MIT', + localLink: 'https://alexa.amazon.com', + connectionType: 'cloud', + dataSource: 'push', + tier: 2, + compact: true, + dependencies: [ + { + 'js-controller': '>=2.0.0', + }, + ], + plugins: { + sentry: { + dsn: 'https://e9ac55f23fe149e78b1eab9ed4bf26ad@sentry.iobroker.net/8', + pathWhitelist: ['@apollon', 'alexa-cookie2', 'alexa-remote2'], + errorBlacklist: ['SyntaxError'], + }, + }, + messages: [ + { + condition: { + operand: 'and', + rules: ['oldVersion<3.13.0', 'newVersion>=3.13.0'], + }, + title: { + en: 'Important notice!', + de: 'Wichtiger Hinweis!', + ru: 'Важное замечание!', + pt: 'Notícia importante!', + nl: 'Belangrijke mededeling!', + fr: 'Avis important!', + it: 'Avviso IMPORTANTE!', + es: 'Noticia importante!', + pl: 'Ważna uwaga!', + 'zh-cn': '重要通知!', + uk: 'Важливе повідомлення!', + }, + text: { + en: 'The new version 1.2.x will potentially change the Names of List Objects when special characters (including ".") are used! Please delete the old objects manually if needed.', + de: 'Die neue Version 1.2.x wird die Namen der Listenobjekte möglicherweise ändern, wenn Sonderzeichen (einschließlich ".") verwendet werden! Bitte löschen Sie die alten Objekte bei Bedarf manuell.', + ru: 'Новая версия 1.2.x потенциально изменит имена объектов списка, когда используются специальные символы (включая ".")! Пожалуйста, удалите старые объекты вручную, если это необходимо.', + pt: 'A nova versão 1.2.x irá potencialmente alterar os nomes dos objetos de lista quando caracteres especiais (incluindo ".") são usados! Por favor, exclua os objetos antigos manualmente, se necessário.', + nl: 'De nieuwe versie 1.2.x zal mogelijk de Namen van List Objects veranderen als speciale personages (includeren) worden gebruikt. Verwijder de oude objecten handmatig als het nodig is.', + fr: 'La nouvelle version 1.2.x modifiera potentiellement les Noms des objets de la liste lorsque des caractères spéciaux (y compris "). Veuillez supprimer les anciens objets manuellement si nécessaire.', + it: 'La nuova versione 1.2.x cambierà potenzialmente i nomi degli oggetti di elenco quando vengono utilizzati caratteri speciali (inclusi ".")! Si prega di eliminare i vecchi oggetti manualmente se necessario.', + es: 'La nueva versión 1.2.x potencialmente cambiará los Nombres de Objetos de Lista cuando se utilizan caracteres especiales (incluyendo "). Por favor, borre los viejos objetos manualmente si es necesario.', + pl: 'Nowa wersja 1.2.x będzie potencjalnie zmieniać nazwę nazw obiektów listowych, kiedy używa się specjalnych postaci (w tym „.”). Okazuje się, że stare obiekty ręcznie będą potrzebne.', + 'zh-cn': '新版本1.2.x将有可能改变名单所列物品的名称(包括“......”)。 请在必要时删除旧物体。.', + uk: 'Нова версія 1.2.x потенційно змінить імена об’єктів списку, коли використовуються спеціальні символи (включаючи «.»)! За потреби видаліть старі об’єкти вручну.', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + }, + { + condition: { + operand: 'and', + rules: ['oldVersion<3.15.0', 'newVersion>=3.15.0'], + }, + title: { + en: 'Format to create Reminder/Alarms changed!', + de: 'Format zum Erstellen von Reminder/Alarms geändert!', + ru: 'Формат для создания Reminder/Alarms изменился!', + pt: 'Formato para criar lembrete / alarmes alterado!', + nl: 'Format om Reminder/Alarms te creëren!', + fr: 'Format pour créer Reminder/Alarms changé!', + it: 'Formato per creare Reminder/Allarma cambiate!', + es: 'Formato para crear Reminder/Alarms cambiado!', + pl: 'W celu stworzenia zmian Reminder/Alarms!', + 'zh-cn': '创建Reminder/Alarms的格局改变了!', + uk: 'Змінено формат створення нагадувань/будильників!', + }, + text: { + en: 'The format used in the "New" states for Alarms or Reminders has changed and allows now to provide more Details. Please see the Readme for the details!', + de: 'Das Format, das in den neuen Zuständen für Alarme oder Reminders verwendet wird, hat sich geändert und ermöglicht nun mehr Details. Die Readme enthält alle Details!', + ru: 'Изменен формат, используемый в новых состояниях для тревоги или напоминаний и позволяет теперь предоставить более подробную информацию. Пожалуйста, посмотрите Readme для деталей!', + pt: 'O formato usado nos Novos estados para Alarmes ou Lembretes mudou e agora permite fornecer mais detalhes. Por favor, veja o Readme para os detalhes!', + nl: 'De formaat gebruikt in de Nieuwe staten voor Alarms of Reminders is veranderd en staat nu toe om meer Details te leveren. Zie de Readme voor de details!', + fr: 'Le format utilisé dans les nouveaux états pour les armes ou les rappels a changé et permet maintenant de fournir plus de détails. Veuillez voir le Readme pour les détails!', + it: 'Il formato utilizzato nei nuovi stati per gli allarmi o i ripetitori è cambiato e consente ora di fornire ulteriori dettagli. Si prega di vedere il Readme per i dettagli!', + es: 'El formato utilizado en los Nuevos estados para Alarmas o Recordatorios ha cambiado y permite ahora proporcionar más detalles. Por favor, vea el Readme para los detalles!', + pl: 'Format używany w nowych stanach dla Alarmsa lub Remindersa został zmieniony i pozwala obecnie na dostarczenie większej liczby dekatów. Wyglądaj na szczegóły!', + 'zh-cn': '新州用于申报或递解剂的格式已经改变,现在可以提供更多的细节。 请见详细!', + uk: 'Формат, який використовується в станах «Новий» для будильників або нагадувань, змінився і тепер дозволяє надавати більше деталей. Будь ласка, перегляньте файл Readme, щоб дізнатися більше!', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + link: 'https://github.com/Apollon77/ioBroker.alexa2#alexa20echo-devicesserialnumberalarm', + linkText: { + en: 'Readme', + de: 'Reader', + ru: 'Читать', + pt: 'Readme', + nl: 'Lees', + fr: 'Readme', + it: 'Readme', + es: 'Readme', + pl: 'Ready', + 'zh-cn': '阅读摘要', + uk: 'Readme', + }, + }, + { + condition: { + operand: 'and', + rules: ['oldVersion<3.18.0', 'newVersion>=3.18.0'], + }, + title: { + en: 'Changes in Smart Home device syncing', + de: 'Änderungen der Smart Home Gerätesynchronisation', + ru: 'Изменения в синхронизации устройства Smart Home', + pt: 'Alterações na sincronização de dispositivos Smart Home', + nl: 'Veranderingen in Smart Home apparaat', + fr: "Changements dans la synchronisation de l'appareil Smart Home", + it: 'Modifiche nella sincronizzazione dei dispositivi Smart Home', + es: 'Cambios en la sincronización de dispositivos Smart Home', + pl: 'Zmiany w Smart Home urządzenie synchronizujące', + 'zh-cn': 'Smart家装置的合并变化', + uk: 'Зміни в синхронізації пристрою Smart Home', + }, + text: { + en: 'Starting with version 3.18.0 smart home device values are no longer synced by default. You need to enable the new state #includeInIntervalQuery existing for each syncable device in the objects in order for the device to be synchronized. Please enable only those that you really need to reduce the requests to Amazon and the Skills and prevent blocking or issues.', + de: 'Ab Version 3.18.0 werden Smart Home-Gerät-Werte nicht mehr standardmäßig synchronisiert. Der neuen Zustand #includeInInterQuery, der für jedes synchronisierbare Gerät in den Objekten vorhanden ist, muss aktiviert werden um das Gerät zu synchronisieren. Bitte nur diejenigen Geräte aktivieren, die wirklich benötigt werden, um die Anfragen an Amazon und die Skills zu reduzieren und Blockierung oder Probleme zu verhindern.', + ru: 'Начиная с версии 3.18.0 интеллектуальные ценности домашнего устройства больше не синхронизированы по умолчанию. Вам необходимо включить новое состояние #includeInIntervalQuery существующее для каждого синхронного устройства в объектах, чтобы устройство было синхронизировано. Пожалуйста, включите только те, что вам действительно нужно уменьшить запросы на Amazon и навыки и предотвратить блокировку или проблемы.', + pt: 'Começando com a versão 3.18.0 os valores de dispositivo doméstico inteligente não são mais sincronizados por padrão. Você precisa ativar o novo estado #includeInIntervalQuery existente para cada dispositivo sincronizável nos objetos para que o dispositivo seja sincronizado. Por favor, ative apenas aqueles que você realmente precisa para reduzir os pedidos para Amazon e as habilidades e evitar bloqueio ou problemas.', + nl: 'Beginnend met versie 3.18.0 slimme thuis apparatuur is niet meer gesynchroniseerd door defect. Je moet de nieuwe staat in staat stellen includeïntervalQuery die bestaat voor elk syncable apparaat in de objecten om het apparaat te synchroniseren. Betrek alleen degenen die je echt nodig hebt om de verzoeken naar Amazone en de Skills te verminderen en blokkeren of problemen te voorkomen.', + fr: "À partir de la version 3.18.0, les valeurs de périphérique à domicile intelligent ne sont plus synchronisées par défaut. Vous devez activer le nouvel état #includeInIntervalQuery existant pour chaque périphérique synchronisé dans les objets afin que le dispositif soit synchronisé. S'il vous plaît activer seulement ceux que vous avez vraiment besoin de réduire les demandes à Amazon et les Compétences et prévenir le blocage ou les problèmes.", + it: 'A partire dalla versione 3.18.0 i valori dei dispositivi smart home non sono più sincronizzati per impostazione predefinita. È necessario abilitare il nuovo stato #includeInIntervalQuery esistente per ogni dispositivo sincronizzabile negli oggetti in modo che il dispositivo sia sincronizzato. Si prega di attivare solo quelli che è davvero necessario ridurre le richieste a Amazon e le competenze e prevenire il blocco o problemi.', + es: 'Empezando con la versión 3.18.0, los valores de dispositivo hogar inteligente ya no se sincronizan por defecto. Necesita habilitar el nuevo estado #includeInIntervalQuery existente para cada dispositivo sincronizable en los objetos con el fin de sincronizar el dispositivo. Por favor, active sólo aquellos que realmente necesita para reducir las solicitudes a Amazon y las Habilidades y evitar el bloqueo o problemas.', + pl: 'Począwszy od wersji 3.18.0, inteligentne urządzenia domowe nie są już zsynchronizowane. Musisz umożliwić nowy stan #include InIntervalQuery istniejące dla każdego urządzenia synchronizującego się w obiektach. Pozwólcie to tylko tym, że musisz zredukować żądania do Amazona i Umiejętności i zapobiegać blokowaniu lub problemom.', + 'zh-cn': + '从第3.18.0版的家里装置价值开始,不再因违约而形成。 你们需要使新的国家能够为各物体的每个可核对装置建立新的国家行动目标。 仅请你真正需要减少对亚马逊和技能的要求,并防止阻断或问题。.', + uk: 'Починаючи з версії 3.18.0, значення пристрою розумного дому більше не синхронізуються за умовчанням. Вам потрібно ввімкнути новий стан #includeInIntervalQuery, який існує для кожного синхронізованого пристрою в об’єктах, щоб пристрій міг синхронізуватися. Увімкніть лише ті, які вам дійсно потрібні, щоб зменшити кількість запитів до Amazon і Skills і запобігти блокуванню чи проблемам.', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + link: 'https://github.com/Apollon77/ioBroker.alexa2#alexa20echo-devicesserialnumberalarm', + linkText: { + en: 'Readme', + de: 'Reader', + ru: 'Читать', + pt: 'Readme', + nl: 'Lees', + fr: 'Readme', + it: 'Readme', + es: 'Readme', + pl: 'Ready', + 'zh-cn': '阅读摘要', + uk: 'Readme', + }, + }, + { + condition: { + operand: 'and', + rules: ['oldVersion<3.26.0', 'newVersion>=3.26.0'], + }, + title: { + en: 'Changes in activity synchronisation', + de: 'Änderungen der Aktivitätssynchronisation', + ru: 'Изменения в синхронизации активности', + pt: 'Alterações na sincronização de atividades', + nl: 'Verandering in actuele synchronisatie', + fr: "Changements de synchronisation d'activité", + it: 'Modifiche della sincronizzazione delle attività', + es: 'Cambios en la sincronización de actividad', + pl: 'Zmiany w synchronizacji aktywności', + uk: 'Зміна синхронізації активності', + 'zh-cn': 'B. 活动统一时间的变化', + }, + text: { + en: 'Starting with Version 3.26.0 The activity/history is no longer queried automatically. If you need this automatic query please enable it in the settings - but only if you really need it! It generates load on the amazon systems and we should try to reduce this as much as possible please!', + de: 'Beginnend mit Version 3.26.0 Die Aktivität/History wird nicht mehr automatisch abgefragt. Wenn Sie diese automatische Abfrage benötigen, aktivieren Sie es bitte in den Einstellungen - aber nur, wenn Sie es wirklich brauchen! Es erzeugt Belastung der Amazonsysteme und wir sollten versuchen, dies so viel wie möglich zu reduzieren, bitte!', + ru: 'Начиная с версии 3.26.0 Деятельность/история больше не запрашивается автоматически. Если вам нужен этот автоматический запрос, пожалуйста, включите его в настройках - но только если вам это действительно нужно! Он генерирует нагрузку на амазоночные системы, и мы должны попытаться уменьшить это как можно больше, пожалуйста!', + pt: 'Começando com a versão 3.26.0 A atividade/história não é mais consultada automaticamente. Se você precisar desta consulta automática, por favor ative-a nas configurações - mas só se você realmente precisar dele! Ele gera carga nos sistemas de amazon e devemos tentar reduzir isso tanto quanto possível, por favor!', + nl: 'Begin met Version 3.26.0 De activiteit/hestory is niet meer automatisch. Als je deze automatische zoektocht nodig hebt, zet het dan in de settings, maar alleen als je het echt nodig hebt! Het genereert lading op de Amazone-systemen en we moeten proberen dit zoveel mogelijk te verminderen!', + fr: "À partir de la version 3.26.0 L'activité/l'histoire n'est plus demandée automatiquement. Si vous avez besoin de cette requête automatique, veuillez l'activer dans les paramètres - mais seulement si vous en avez vraiment besoin! Il génère de la charge sur les systèmes amazon et nous devrions essayer de réduire cela autant que possible s'il vous plaît!", + it: "A partire dalla versione 3.26.0 L'attività/storia non è più richiesta automaticamente. Se hai bisogno di questa query automatica, abilitalo nelle impostazioni - ma solo se ne hai davvero bisogno! Esso genera carico sui sistemi amazon e dovremmo cercare di ridurre questo il più possibile per favore!", + es: 'Empezando con la versión 3.26.0 La actividad/historia ya no se pregunta automáticamente. Si necesita esta consulta automática, por favor, activela en la configuración - pero sólo si realmente lo necesita! Genera carga en los sistemas amazon y debemos tratar de reducir todo lo posible por favor!', + pl: 'Od wersji 3.26.0 Aktywność/historia nie jest już automatycznie kwestionowana. Jeśli potrzebujesz automatycznego zapytania, co pozwalasz w ustawieniach - ale tylko wtedy, jeśli tak naprawdę potrzebujesz! Wykorzystuje on ładunek na systemach amazonek i powinniśmy starać się zredukować to, co jest możliwe!', + uk: 'Починаючи з версії 3.26.0 Діяльність/історія не передається автоматично. Якщо вам потрібен цей автоматичний запит, будь ласка, ввімкніть його в налаштуваннях - але тільки якщо вам дійсно потрібно! Ми можемо самі зателефонувати одержувачу!', + 'zh-cn': + 'A. 导 言 活动/法令不再自动提出。 如果你需要这种自动问询,请在环境中这样做,但只有你真正需要! 它给马纳区系统带来了沉重的负担,我们应尽量减少这一点!', + }, + level: 'warn', + buttons: ['agree', 'cancel'], + }, + ], + installedFrom: 'iobroker.alexa2@3.26.5', + installedVersion: '3.26.5', + host: 'NanoPi-R5S', + adminUI: { + config: 'materialize', + }, + }, + native: { + cookie: 'session-id=258-5154358-9276845; session-id-time=2357908246l; ubid-acbde=262-3880762-6890826; x-acbde=h?UBRmGVZrLL6k7jLGvsDLJMRW2UoY4Hz@TcsclYsy6y75PmFH6LsAvVCg@TSid8; at-acbde=Atza|IwEBIHjKvwer_K_uekSTsVERqURDvl6C7wjXjOrycGcaNAW9WLXTtfuYrx5oJyBvnsj9c9sgC7elIZc_CZ4TsLtCPqRkvx7hDmURzO1eFcn7Ihs7GaZYarMX5EENAIeHXVDftDBjxrSRbtVv1wQ8pdwr9nR49r0UBYEJ-T3oHuD6eYw9WkCczKkX20XFMFHpmQMuTmUzkdFQH7xtL6ZHeTrB6MCOqmj-nealzLCYqBU_k3adjIid-kAhW-orM8ouPwi-De4DhPa0jopB-qj4vx3DhuPNLrEhYfVJ3NRIXeE-Q4x9yW6s1W1l1qf2ctTjb_5_FjFULdC1hyIHRXGAYB9inJdao5SWQ-meIcc-hLge39p24A; sess-at-acbde=kYcW20A6TYrh4Oj14kTMAkDulN/1hwrEn4uk4x1QBac=; csrf=771780681', + csrf: '771780681', + cookieData: { + loginCookie: + 'frc=zBsB7pn0QNBBSVho52Ts+UIcO5XMgOrtTrotPBCfyDQK7S6M9YW8JmtVO+AkjhSNB4NFRMjLZCvFtF7rql9AtcHwUsU2Ily2y1SAekkf8IUmHFzIw5R7GQkghTkpOinyFeXzNESlJ/R36QYifjAEmjuAXbkLWxHlTRf0Cjd1kgRRcFkYrtpwjnkqNs6s98Q+b4xQy8bU6YUD7nCyx1yO+tLgvwG8vV634OFyTX1kXfq/GWHWPeqJbNjrMnvkCW7EoU146vUI6jQvWnk52ivj2NEbgiFO4vNyE0p7jj70vqTMQcWpRdcdodYY8EWAm5TYTxxQOWROcslOQBmSMumc0dLNe7aZwtYp82wyU+ewD+S7o0Ntee3yBL6yY16VVZrhMlMMtbbkWTyyH/Ebwff0xsybFJSP7dL7SA==; map-md=eyJkZXZpY2VfdXNlcl9kaWN0aW9uYXJ5IjpbXSwiZGV2aWNlX3JlZ2lzdHJhdGlvbl9kYXRhIjp7InNvZnR3YXJlX3ZlcnNpb24iOiIxIn0sImFwcF9pZGVudGlmaWVyIjp7ImFwcF92ZXJzaW9uIjoiMi4yLjQ4NTQwNyIsImJ1bmRsZV9pZCI6ImNvbS5hbWF6b24uZWNobyJ9fQ==; session-id=134-0786836-5135341; session-id-time=2357908245l; ubid-main=133-9250336-7981229; x-main="931rc1kp56?Ty7OaXNuUWAub8MU5vE9YH@kf1y5CJxCBpYQJMGO6vlvz0rItabjL"; at-main="Atza|IwEBIOXtyeDN8pVDaQ8HbfwpnCADvR7FMqF_ZYrKhf_tcJ6zPo5h2fm0Xwoe6P-8C6c4XwYlFV_D-lX4jw8LPC3gbjJMYULh7amSiA7n9agi9FjXiPF6NOdR6q5EVzvCx_FiLusImLxXIDgDx46XNp9_Z1wlS5KxgJKVsVHcN4lJfeYX3dM6AuLg2pIl3mZYULF-dZXJQcR6kGX0MokoYOEyuqcrfD0pBf8tb6pFHb60wZF4pn5qqqRB9cA3iaVnWJkbRhTbrTBecYt7nvu1MScSlssOH8SRFI7FQddzTUKQ05G2SWu6CTy6vpZLaWMElCbCjMPOqGdUS8VdtSdBztKOU6ZcW2EvUahE7pMgwAZeFghxQw"; sess-at-main="dkEX1wliQMJGtUh3Rjk1QoPnwbTLQWHDJP7g0/ZZmTE="; session-token=KsooP9cbMVvuS6uPyuqMhnxGddGl1r/J0PVCyUZOhe2tYBmmG7kmLRe5IlYGGYbOur0p1k3y5Kzf7X46SrtmRxTle6V9fAeXZYaAt/X96VeXmTNB5/wkTrSn3xgsWxmQqqglrvVtbkjg31PivZanIp3VHdyIF4CBXvS6hCyoZ51X508bZIf6Ye6Ld9K66seMComhMhmcKGVCsST5upieC2kSoSvU0HIgkeZgAG2WC0NqBquOpXgF6sz8nrVyGw5A83qN11oxxU6WPk8aRR27rL/Zf20GWmkfYWlW6cQ4U653FDnG94Uv+/IHkPvwbJppZhjYHqi/RXbS5CNcGrkUsIDjHf/G1ws5J+WRtLtibAG2rTRD5hPdp1+nhNh2A5sE', + frc: 'zBsB7pn0QNBBSVho52Ts+UIcO5XMgOrtTrotPBCfyDQK7S6M9YW8JmtVO+AkjhSNB4NFRMjLZCvFtF7rql9AtcHwUsU2Ily2y1SAekkf8IUmHFzIw5R7GQkghTkpOinyFeXzNESlJ/R36QYifjAEmjuAXbkLWxHlTRf0Cjd1kgRRcFkYrtpwjnkqNs6s98Q+b4xQy8bU6YUD7nCyx1yO+tLgvwG8vV634OFyTX1kXfq/GWHWPeqJbNjrMnvkCW7EoU146vUI6jQvWnk52ivj2NEbgiFO4vNyE0p7jj70vqTMQcWpRdcdodYY8EWAm5TYTxxQOWROcslOQBmSMumc0dLNe7aZwtYp82wyU+ewD+S7o0Ntee3yBL6yY16VVZrhMlMMtbbkWTyyH/Ebwff0xsybFJSP7dL7SA==', + 'map-md': + 'eyJkZXZpY2VfdXNlcl9kaWN0aW9uYXJ5IjpbXSwiZGV2aWNlX3JlZ2lzdHJhdGlvbl9kYXRhIjp7InNvZnR3YXJlX3ZlcnNpb24iOiIxIn0sImFwcF9pZGVudGlmaWVyIjp7ImFwcF92ZXJzaW9uIjoiMi4yLjQ4NTQwNyIsImJ1bmRsZV9pZCI6ImNvbS5hbWF6b24uZWNobyJ9fQ==', + deviceId: + '313734464232453032423736433344413233384644334542363741324346463923413249564c5635564d32573831', + deviceAppName: 'ioBroker Alexa2', + deviceSerial: '47b5837bb9c8806acb86e4b663e772bb', + refreshToken: + 'Atnr|EwICIAGqbSYJv6kRnrEbguc-WEzrPFEVBER0idMIRMtXh5f9HBtkEkinIqwjGwdKM4gg7_-yt5E2JRVfpPfqMDR8BFNkCuju9vwtdmiqWkfrqV_JRcZByxzXMl0YMzBXQ8SzkbV2b6VNnqohF7qm5xTPI2e7BN9sCv9YxV3fI9rLXlVIuB6ps6q_6wfu4yWpcqm2x22IetSy5czFCd7hSsqc2I4G1YeAelUmhkLHk1a6KyzRaIhUhGS9CN7Z0FqJc2B6bIKFpL0qQysA6e7ghQbfLQ_F8TfWoFyTZPbb-ZS-PBDXCOcZ6bzka5GM7ycVZLA4_nQ', + tokenDate: 1727188245780, + macDms: { + device_private_key: + 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCbZmDZbznu/m7fALay2S7VOBCf+i5MSmeGN6at9rbdN/+RxIIFfpi8yZCnp45UyyeRybkEviW+BjSvPsa4TIrEVTZtNkYhvufGmBZCJfaIul24ECXCNGVQ6fENmGXmXPybstXCGbwOmhZQJqudG0qKmWUHe0J9wvOSbwG+oO7nVcyzsgwwe5uuy6qDR0oc/JBSTsr+ClnlTtCzvXDV4X4QEYm58MQl7BLv2oEoPP1SIBbSiiH5LZ3cKzCfFczZL7TR9WaPiXPsIgY68U3Jc0deaYSkyAEEWPMPh7RJeYTTxP3SFyq3en8kyFwip3cQ8I4UBul7xkd5CPCPV600NbOnAgMBAAECggEAcTH/9iJ49sfLBxHEAz8ESDgQlBduxg+knTXIagu+ZCG4PfwAIfR3WX0Rq633lXhuGFnyNaw0XdizY7u8kN7gbecMQD06lLY0qop6HDD/BdWLEtpgRrhX3Lqr5hVOlKDDOL7pyfto6tH+0t94PnZ0s8TMvMhiRK1PMyk9AhjELSlFxWHNd3cyKPzCE34xMouTYow5+0yumIypcnwuPkDrepdwlEYjzA1LleY6F/5m3OztpXyNw+7qPMDBpVkM73eNKoe8nmPCNEeuN1w7R9J6e8ukW0Zs9NQ2/uKJZfLr4e5b9LBFWk3yXN16W8UU8URUSJSYJ7tVzRq3NDg0KnHDwQKBgQDNAUvovpcXHnDSErXyQjPVHuyltKcyoupBxG7p9n5PKJmjBCaf08Y58KqNVt3M7I5iVGXH95gPds4Bq2HaHNVw7ryL1sUvhvbcQ6SUUdchHiBqSJIhUQCXPbMLKe6mtb3nYW1mGsn/QAcprP+eSb1fnD986q4cxDs0t3hPWeW2NwKBgQDCDjsCAfM5XlPbjzVOdJRWx6lWNPaErhauwBXtD2Bip+qk2SAVJMj64c/dhNsEiMU504j4AeGAIhnTs4p+ZYpHTvkxsRibZdsLQRC2qCzMdUyx8gQWD1b3ICCSeA5OVKDghNNI+sDXWnF4Vp6xwgjGxY2yc1LuyDwl69iWEiM2EQKBgQCacVibvkIbg65hRQFXwnJEI+kKqX+w0TWEWJVqo23i+uZL/ouOqz/SVLJYitHMWYanI4gOT0R6mfl3HoM4i7JtQx4+h43EUXxW0osBxmo5I/YtvACDIwA78JqbVXrak16/GxIM8y+sobMDvbZRrKIDjrXxyOdk+pzUCUiVF1fMnwKBgQCVI9q18Em+DYDlfWq6oV5gU5MRbiMIVcOZCofPacHqEKOFjlnZ5iuQpXvcA/9PvM3XY3whH1Dv6UVwLsyB2AguRcO/LRx8UgvG2nq95wKHIJ+RIy+AxMlRpJ9j8mEMUn5SD8NSk2UiHaCXm/rbIwUbvzjnrTpPyhRwEJKkw8vMAQKBgHeBc+f6HVn2Gg2EuGHoIp+6ozp7y4QDAqfVXUcI+kcSNQm4IkzyfPDMyE1qCMvH1SN3Hn+XdhGNqQpTqzMHfmDfMoHKMrZ/R9QzQiRsT0zmRRHKjWI2cRIFNueHP2ta733STZqROKbPVDcqrZ+wyoVCIUGQA+2knSNRaPAg7S8y', + adp_token: + '{enc:9suBgetjYDS2XdPokpZYv0T+nkqrn3pN1KtFioFX+uKaACo2/eHEHTfa5D2ImY8Bz2n+g8b5jsE/oSTjPiI0WpVvmRlXHqEnmHVrPVRyFK+uD/amWurb1GcGqpFjY5lQV7rvH0/RLdE11fdpTwSDTx/7K6wZwKIXisxRAHBw6Hf4uQMVDbbft2PV6sHh+GWlhugm1896p5ku6YFX6wnnCT+RMtAZjCzRynzpY3qyMHbRy7vuu1A6c/3xtHzTo6bEbCGj5WylRso605OEoQsFKSHIQaZ2xcDXEJshYZ49gKfgOIaZ5xZbtq3m1YWOr4ZNFHlZwTaGKhKgFx3I5YSWJBIrUr4XQ26BzNPT2nYTuliqoDg8E3oXa9RZJNyybAp63lo2vBnTi+5nH8RGG6DCQCWIoCJ/UX8uJmjDES045LHmqp+kEy0IMsms98jmdRXWcV70n7vSlEvR9Il9DkxFS/d4U/8P3JoaW2HurPaoFEzKIerxFUPfa8Ia+w7MdXBS0Nmau/9QBBRgVjhK7K1gJqK8ygJ0pcXOb5b2SXfgZ+VQ3TjI37NjegZWJ7qv5abeIN6PRXjQjDsyAHxpDVy9tvjPJoIz+8ZmYej/FjHjhXszah3s3DFddFBc9oH7QjRQNY6RLXqh2ibnfNy5K4nyGahFxLIyVJMvH6UtmU53UQkeCTJVUL+bre69F3UCS9BI8RhktOA94zmseiZ/10vkcdfszQRONmrxbgo5akzkVkcOEw4bZCkcLS7/nwH3dzURvOF/tEZfRPhDnRRDgKzEJnNnoRCeyg0YwsKGh82dO75YToJc8ayukRlSDF1j92LAExLBE+WXPKMMb3e3qIh7q7TunsSVtb9/LfysRPLUOvS8EOfFysHszhTdbk+Fggolv60LcJphnoIOa1MwJpr+q5Erz5+M0X8JAygZ2cqin7Mrj1D7pBoSHi2LYesvHcaVmiTM7mh4QNNKwi499VIy+3ZIysdKr1Zbw3HujgBZbHwVRKljoDtkjABERpbqoGIjip6rjtF58Csex8nIYKatiEdT53HIvQsW/MNIwatUTx4Lbs0SjxpCu23UYQW3xuXx}{key:A/U8PDpVlMEfoaL77nNuQAPhQbL8nAV5JIaTMSQuHff0rUYcDPZise6iQLp7Zu6r6T7MRhNdBzHxINO1r/zQBVHDr1Y1B7++dw2yHYlhnCVUf+jv+jPBiG8XBb7djHjxYCDjsRTDo3km7L5wwjnr8tN7esq8klQ2Me9hvoJl+vJ+hrg0KmHDvA6kq5a/ZWf1GfyOnRKlvb0YZqDMQYu/EikPB71lSL0ZZOMa+zwewTDYl0Jau5Ne6y5Ap+4J4UEf4GDbD0YPbulPipLmqM5roMzKTKuur2XU30GFu9CmPe5+xca5TLMsV6JeXECOac2W7aixfg6eP2PZCUPJP/4t/g==}{iv:lPenC5UvOXWN8mtpm7kiOw==}{name:QURQVG9rZW5FbmNyeXB0aW9uS2V5}{serial:Mg==}', + }, + amazonPage: 'amazon.de', + localCookie: + 'session-id=258-5154358-9276845; session-id-time=2357908246l; ubid-acbde=262-3880762-6890826; x-acbde=h?UBRmGVZrLL6k7jLGvsDLJMRW2UoY4Hz@TcsclYsy6y75PmFH6LsAvVCg@TSid8; at-acbde=Atza|IwEBIHjKvwer_K_uekSTsVERqURDvl6C7wjXjOrycGcaNAW9WLXTtfuYrx5oJyBvnsj9c9sgC7elIZc_CZ4TsLtCPqRkvx7hDmURzO1eFcn7Ihs7GaZYarMX5EENAIeHXVDftDBjxrSRbtVv1wQ8pdwr9nR49r0UBYEJ-T3oHuD6eYw9WkCczKkX20XFMFHpmQMuTmUzkdFQH7xtL6ZHeTrB6MCOqmj-nealzLCYqBU_k3adjIid-kAhW-orM8ouPwi-De4DhPa0jopB-qj4vx3DhuPNLrEhYfVJ3NRIXeE-Q4x9yW6s1W1l1qf2ctTjb_5_FjFULdC1hyIHRXGAYB9inJdao5SWQ-meIcc-hLge39p24A; sess-at-acbde=kYcW20A6TYrh4Oj14kTMAkDulN/1hwrEn4uk4x1QBac=; csrf=771780681', + csrf: '771780681', + dataVersion: 2, + }, + alexaServiceHost: '', + email: '', + password: '', + userAgent: '', + acceptLanguage: '', + cookieLoginUrl: '', + proxyOwnIp: '192.168.178.73', + proxyPort: 0, + proxyListenBind: '0.0.0.0', + updateConfigurationInterval: 3600, + updateStateInterval: 300, + updateHistoryInterval: 300, + usePushConnection: true, + proxyOverrideIp: '', + resetCookies: false, + historyIgnoreEmptySummary: false, + macDms: { + device_private_key: + 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDm8atR7PEwY9mR8Vw5xaMwtaE9mGxFrBnnE3fdz78gP5aB25W5Th/vcWzYZD91SVvu3MG5kdXPYb3qBdBpOhUiwtfRlECPRYn99ubvjn0vcz2Jb0v0teZpd5dbcM3aBid9pt3aL0qC5Xzq03gZoUc3ZnB0/vVfIl9YEWWL/JU4D0n/1ZLdfS2QE/2Rbuc35t/85CNeePk4fh/Bk3We5osIwG87pRrxxbM6ityyH+CYZV5aHcFrpqn0KDrug7Coj1vRiKtGDg0N/tIHkFm5ywSSh6J9QtYchom8Zjb4ksE75/XPnerLEwxtoAZjVjNuv3YyLtsns685vle4QCKjIr1vAgMBAAECggEBAL1wmibu5P3bujokMZHWVEH9i5FaOd6BCRJq/tV9t3r9jjlhZZUGx92DPlTXDtLn5Tiv712Iikm+FKomMMpQccv85kotgTPFSCeCY/c3++pzbpQRLs5CdAoppofEpadlivlgavWx+z4af3ilFQx5JlEEf9UI20A5ktpMEu9ctw6utMaSAK0CYcXDRI+lDncc61ygjGYoHVA8ZGmxl9yhiHnvtGfDrvsgM2ZE7u6wKM7FVKP6lDxkUTQxLbktvSDnNg6jMNd22ABBdoJsxfUrwXOcdW97p9UpJX+5niRWtilizReI05OyveL0JnOL1JB08IOwF5+mUCl0c95FwLgCPPECgYEA/FkrSm2vM6fsDUVxk+w3/v6Epk2flbrHLKS0GyMqHTf+vArtOkgn3bFWUsrS4/fQ7rdJ1+pFA+2KAGkJoWNQ53v60SBCKOhEmYDQfr9urBEZg5VzbcysbF+Gl6iJPSWLj7GQOTVGvg3fonaq7ca8MkW4C8EPGifObfgcW9uaPocCgYEA6kk1FGDp33yT31lsyfCc6NzUd37leiMvkCdEk5VVq13jEMyhWY0q4voRUWnuaUlpL4nDrW7YWkivJMMb7FB8Q+o7XNPxrOcr8qY/qSOjmLIM8A/i/faUOrO44laBMSbp7r39fPP+WN70JrmMNYar8KXRKak3Qxpc6xhAsjQ4m9kCgYA7uIasSKUMHpOY2HR2w5LFAEs4aGp6LwfwItKVEY9n9taMfjGCd40nxE5frayXUxDZTftl5AWNVmwwiKtEzJJbFlZXo8DEmaOSiI/PT1LL2gglwfrdY3Dy/PCHd9Vy6S3MRgOR5m/ljrb8ZgUx3LSxWRqjfX8re3w5PlzHyIMKhQKBgQDmwQYTtUSEh2oJ0UUyPNf/DwoBTC3vN1qwa8zCY5KGf6mWsUW2MzFrb4vBGUnlz5VXaiQd3RAhFHfVCIqnHbrXFYw0aNgfSW1iyFXpXJ3UVoIhrDQRmVzz2HIgE72ZUM+WAvD5skPw+l+VCKnNSoBtPJSfqPgyEnQ0ZaXLH14mOQKBgA7XoFHEhZT3iFcV6jeVeFMbMrOFpAOeM6Y5ALUHjG9kt5EyCx6pqPyhqcfM43LHxFRkxqNXo+J76/r168RsYMx6iI4EBzYN+6rvVhLuSQYTpUxRAoqHG+kiac3YiVOXv20ucEtx5u7mvzJ2QhqLjn910smIjeaiR7c6tjqbPXY/', + adp_token: + '{enc:lvfW1oQ/JS4A4j5Ikf+a3Qfg7jsJc3xGh/Bnwk6oyunH7jHuFUJ+qK9BZVNKJgkSFCzJeyjMXrrPi/0S1IXnWET09eqBavwdoREnbDP+fri/MgzR75hxUoMhVeWLQmkjmclFxlXlqNBcyLNVBKYajzNd43mzUkD8St1Tv7F9UkP7R6nlZpk++L4tFWT9TS7HBP2oLf4IGZ0qLfOxEGEeISlJ1xxRF/fw2FIp6GIApP+XapoTlES+iVIg93Gzo8tY3LNGyTPAH8QKhReZz3xD5ltz9hR3Jd1vG28E0wxnXbqob57enDqUceQxbfbAkSp8EjHU3UJ4f98YLncBe2MaJVHK/SQ6aSgvMh/XVAbZEW1de5gBy6f2Ji5GauOQ9gJjcef89zLgiZgkT8Nqv+ThNOzgUCGWrvnvQbF1EHHpCffu97VExqk8muIY+RZoub3hkbpmO+lmEYEoY/MtoA8/8BJSAsc/FW3jXnuz9xBGnFnPa9CSj7883ukwQCwYjo78SZPn74eciVcBhr604yC92zeQdjjUxq5pOcUaD9mcumNr9KgTg/9QhY9In3JE7rqaPJAgFc8KL7F7I6CD9RuHW/q0Hby35bXt1d1WQa3HKF2EelT8fO8Wb0NnkbsUwMiUJUUvvFB5u1/J7DgOz7zmM9OTtQRpDc4ohF63QH1qC/OZKgnXs3wOQPiBTosMixMAwVo6bPbAlnwV3QziaFpp4fOwWW1IIyVBFuKwvljOcUJ0hWGQb3UobYNuJv+PoOW828IYzc2m/rmP+xatsvmo/G5mSrMmP10YZiqyG0LDE9Nbd2gt2sTrymgJqlfmJLDu0ianS/0PXZNlfKPfSPUcEZ4tLpRUWG6Q3gvrrtpXXGPE7q18vRyOit6dxX0D/BxhacZoh8i4ZE4ypiuwgou2QBSWds0ZvJ0ZAPK/WIz0VHWdkbYKImb2ajQRu0z6XIlY9gc/9AVpjd4PLvil5ldKctX4t2C4ewxh6/+qsFc+oBBh49bAc15wnuYtR23Br7QF8bF+KbSdEHgO93BbuJm3hBelSZbO5rVzHNwQJslcrI0=}{key:og9vy1cbb1Ks3VHQoc0sRslm0Zi+BIKd/+8bqudLj7dZ9ehK5vQ4dbJxo+SsNNIjYaPE3J9jINiaEjSxJ9cwJM6cr9jjE8iLLOi3evJTdMMcyyvd8u+2oc46ed3Q1MD0w8GKOXRjoqhsLAjcYSwqv0BHzs7NvOHhm0P4f8y46ssSiTm1U8k6+NMWLz/W30J8PLR9LmpsO6rHJFV2VeIjBpZIEGSZZFNf+k666KLHOuJYd4/sWqa1YLPbObnJIxWeD6+LtikzYOQLOm1VbhcdjdjWfh6w9eMaNokQy8hwBf4gKX5ExKg8ZRAa4nFwtHpN0d3eF6we4Rn2U6oVP867lw==}{iv:r21I4KOojFyiwoHAcPEiyA==}{name:QURQVG9rZW5FbmNyeXB0aW9uS2V5}{serial:Mg==}', + }, + includeAppDevices: false, + synchronizeLists: true, + synchronizeSmartHomeDevices: false, + autoQueryActivityOnTrigger: false, + }, + from: 'system.adapter.admin.0', + ts: 1727188280954, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If communication with alexa works', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.cookie', + type: 'state', + common: { + role: 'text', + name: 'Alexa Cookie', + type: 'string', + read: true, + write: false, + def: '', + }, + native: {}, + }, + { + _id: 'info.csrf', + type: 'state', + common: { + role: 'text', + name: 'Alexa CSRF', + type: 'string', + read: true, + write: false, + def: '', + }, + native: {}, + }, + ], + objects: [], + user: 'system.user.admin', + }, + 'system.adapter.devices.0': { + _id: 'system.adapter.devices.0', + type: 'instance', + common: { + name: 'devices', + version: '1.1.5', + title: 'Manage devices', + titleLang: { + en: 'Manage devices', + de: 'Geräte verwalten', + ru: 'Управление устройствами', + pt: 'Gerenciar dispositivos', + nl: 'Beheer apparaten', + fr: 'Gérer les appareils', + it: 'Gestisci i dispositivi', + es: 'Administrar dispositivos', + pl: 'Zarządzaj urządzeniami', + 'zh-cn': '管理设备', + }, + desc: { + en: 'Manage and create devices for using it in other adapters like material, iot,...', + de: 'Verwalten und erstellen Sie Geräte für die Verwendung in anderen Adaptern wie Material, iot, ...', + ru: 'Управляйте и создавайте устройства для использования в других адаптерах, таких как material, iot, ...', + pt: 'Gerenciar e criar dispositivos para usá-lo em outros adaptadores como material, iot, ...', + nl: 'Beheer en maak apparaten voor gebruik in andere adapters zoals materiaal, iot, ...', + fr: 'Gérez et créez des périphériques pour l’utiliser dans d’autres adaptateurs, tels que Material, Iot, ...', + it: 'Gestisci e crea dispositivi per utilizzarlo in altri adattatori come materiale, iot, ...', + es: 'Administre y cree dispositivos para usarlo en otros adaptadores como material, iot, ...', + pl: 'Zarządzaj urządzeniami i wykorzystuj je w innych adapterach, takich jak materiał, iot, ...', + 'zh-cn': '管理和创建设备,以便在其他适配器中使用它,例如材料,iot,......', + }, + authors: ['bluefox '], + keywords: ['ioBroker', 'devices', 'material', 'iot', 'Smart Home', 'home automation'], + license: 'MIT', + platform: 'Javascript/Node.js', + connectionType: 'none', + dataSource: 'none', + tier: 3, + icon: 'devices.png', + enabled: true, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.devices/master/admin/devices.png', + readme: 'https://github.com/ioBroker/ioBroker.devices/blob/master/README.md', + loglevel: 'info', + noConfig: true, + onlyWWW: true, + singleton: true, + type: 'general', + eraseOnUpload: true, + mode: 'none', + adminTab: { + singleton: true, + name: 'Devices', + }, + globalDependencies: [ + { + admin: '>=5.1.0', + }, + ], + installedFrom: 'iobroker.devices@1.1.5', + installedVersion: '1.1.5', + host: 'NanoPi-R5S', + adminUI: { + config: 'none', + tab: 'html', + }, + }, + native: {}, + from: 'system.host.NanoPi-R5S.cli', + ts: 1686635392633, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [], + objects: [], + }, + 'system.adapter.shelly.0': { + _id: 'system.adapter.shelly.0', + type: 'instance', + common: { + name: 'shelly', + version: '8.2.0', + title: 'Shelly', + titleLang: { + en: 'Shelly', + de: 'Shelly', + ru: 'Shelly', + pt: 'Shelly', + nl: 'Shelly', + fr: 'Shelly', + it: 'Shelly', + es: 'Shelly', + pl: 'Shelly', + uk: 'Shelly', + 'zh-cn': 'Shelly', + }, + desc: { + en: 'Integrate Shelly devices via CoAP or MQTT', + de: 'Shelly-Geräte über CoAP oder MQTT integrieren', + ru: 'Интеграция Shelly устройств через CoAP или MQTT', + pt: 'Integrar dispositivos Shelly via CoAP ou MQTT', + nl: 'Integrate Shelly apparatuur via CoAP of MQT', + fr: 'Dispositifs Shelly intégrés via CoAP ou MQTT', + it: 'Integrare i dispositivi Shelly tramite CoAP o MQTT', + es: 'Integrar dispositivos Shelly a través de CoAP o MQTT', + pl: 'Integracja Shelly poprzez CoAP lub MQTT', + uk: 'Інтегруйте пристрої Shelly через CoAP або MQTT', + 'zh-cn': '通过联合方案或技合中心将全套装置纳入', + }, + license: 'MIT', + authors: [ + 'Thorsten Stueben ', + 'Apollon77 ', + 'Matthias Kleine ', + ], + docs: { + en: [ + 'docs/en/README.md', + 'docs/en/protocol-coap.md', + 'docs/en/protocol-mqtt.md', + 'docs/en/restricted-login.md', + 'docs/en/state-changes.md', + 'docs/en/faq.md', + 'docs/en/debug.md', + ], + de: [ + 'docs/de/README.md', + 'docs/de/protocol-coap.md', + 'docs/de/protocol-mqtt.md', + 'docs/de/restricted-login.md', + 'docs/de/state-changes.md', + 'docs/de/faq.md', + 'docs/de/debug.md', + ], + }, + platform: 'Javascript/Node.js', + mode: 'daemon', + icon: 'shelly.png', + enabled: true, + compact: true, + extIcon: + 'https://raw.githubusercontent.com/iobroker-community-adapters/ioBroker.shelly/master/admin/shelly.png', + keywords: ['Shelly', 'IoT', 'CoAP', 'CoIoT', 'MQTT'], + readme: 'https://github.com/iobroker-community-adapters/ioBroker.shelly/blob/master/README.md', + loglevel: 'info', + type: 'iot-systems', + restartAdapters: [], + connectionType: 'local', + dataSource: 'push', + tier: 2, + plugins: { + sentry: { + dsn: 'https://4d0cc16e06844e6d9b930659db1f0492@sentry.iobroker.net/19', + pathWhitelist: ['@apollon', 'shelly-iot'], + }, + }, + adminUI: { + config: 'json', + }, + globalDependencies: [ + { + admin: '>=6.0.0', + }, + ], + dependencies: [ + { + 'js-controller': '>=5.0.19', + }, + ], + installedFrom: 'iobroker.shelly@8.2.0', + installedVersion: '8.2.0', + host: 'NanoPi-R5S', + licenseInformation: { + license: 'MIT', + type: 'free', + }, + }, + native: { + protocol: 'mqtt', + httpusername: 'admin', + httppassword: '', + polltime: 15, + autoupdate: false, + updateUnchangedObjects: false, + logDebugMessages: false, + saveHttpResponses: false, + bind: '0.0.0.0', + port: 1882, + mqttusername: 'mqttuser', + mqttpassword: '$/aes-192-cbc:d290453a44a1417c37a482a298052b39:c9eb76a13626bf7b61dcb6c03761b68d', + qos: 0, + coapbind: '0.0.0.0', + blacklist: [ + { + id: 'SHBDUO-1#123456789#2', + }, + ], + }, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['mqttusername', 'mqttpassword', 'httpusername', 'httppassword'], + encryptedNative: ['mqttpassword', 'httppassword'], + notifications: [ + { + scope: 'shelly', + name: { + en: 'Shelly', + de: 'Shelly', + ru: 'Shelly', + pt: 'Shelly', + nl: 'Shelly', + fr: 'Shelly', + it: 'Shelly', + es: 'Shelly', + pl: 'Shelly', + uk: 'Shelly', + 'zh-cn': 'Shelly', + }, + description: { + en: 'These notifications represent news of connected devices.', + de: 'Diese Benachrichtigungen stellen Neuigkeiten über angeschlossene Geräte dar.', + ru: 'Эти уведомления представляют собой новости о подключенных устройствах.', + pt: 'Essas notificações representam notícias de dispositivos conectados.', + nl: 'Deze meldingen vertegenwoordigen nieuws van aangesloten apparaten.', + fr: "Ces notifications représentent des nouvelles d'appareils connectés.", + it: 'Queste notifiche rappresentano notizie di dispositivi collegati.', + es: 'Estas notificaciones representan noticias de dispositivos conectados.', + pl: 'Powiadomienia te stanowią wiadomości o podłączonych urządzeniach.', + uk: 'Ці повідомлення представляють новини підключених пристроїв.', + 'zh-cn': '这些通知代表了连接设备的消息.', + }, + categories: [ + { + category: 'deviceUpdates', + name: { + en: 'Firmware update available', + de: 'Firmware-Update verfügbar', + ru: 'Доступное обновление прошивки', + pt: 'Atualização de firmware disponível', + nl: 'Firmware-update beschikbaar', + fr: 'Mise à jour du firmware disponible', + it: 'Aggiornamento firmware disponibile', + es: 'Actualización de firmware disponible', + pl: 'Dostępna aktualizacja oprogramowania firmowego', + uk: 'Оновлення прошивки', + 'zh-cn': '可更新的固件', + }, + severity: 'notify', + description: { + en: 'New firmware update is available for your devices.', + de: 'Neues Firmware-Update ist für deine Geräte verfügbar.', + ru: 'Новое обновление прошивки доступно для ваших устройств.', + pt: 'Nova atualização de firmware está disponível para seus dispositivos.', + nl: 'Nieuwe firmware update is beschikbaar voor uw apparaten.', + fr: 'Une nouvelle mise à jour firmware est disponible pour vos appareils.', + it: 'Nuovo aggiornamento firmware è disponibile per i tuoi dispositivi.', + es: 'Nueva actualización de firmware está disponible para sus dispositivos.', + pl: 'Dla Państwa urządzeń dostępna jest nowa aktualizacja oprogramowania firmowego.', + uk: 'Нові оновлення прошивки доступні для ваших пристроїв.', + 'zh-cn': '您的设备有新的固件更新 .', + }, + regex: [], + limit: 1, + }, + ], + }, + ], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: { + en: 'Meta storage for user files', + de: 'Meta-Speicher für Benutzerdateien', + ru: 'Meta Storage для файлов пользователей', + pt: 'Meta de armazenamento para arquivos de usuário', + nl: 'Meta opslag voor gebruikersbestanden', + fr: 'Stockage Meta pour les fichiers utilisateur', + it: 'Meta storage per i file utente', + es: 'Meta almacenamiento para archivos de usuario', + pl: 'Meta storage for user files', + uk: 'Зберігання мета для файлів користувачів', + 'zh-cn': '用户档案的储存', + }, + type: 'meta.user', + }, + native: {}, + }, + { + _id: 'info', + type: 'channel', + common: { + name: { + en: 'Information', + de: 'Information', + ru: 'Информация', + pt: 'Em formação', + nl: 'Informatie', + fr: 'Informations', + it: 'Informazione', + es: 'Información', + pl: 'Informacja', + uk: 'Інформація', + 'zh-cn': '信息', + }, + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + name: { + en: 'Devices connected', + de: 'Geräte verbunden', + ru: 'Приборы подключены', + pt: 'Dispositivos conectados', + nl: 'Vertaling:', + fr: 'Appareils connectés', + it: 'Dispositivi connessi', + es: 'Dispositivos conectados', + pl: 'Device połączone', + uk: 'Пристрої підключені', + 'zh-cn': '联系人', + }, + type: 'boolean', + role: 'indicator.connected', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.update', + type: 'state', + common: { + name: { + en: 'Update firmware version on all devices', + de: 'Firmware-Version auf allen Geräten aktualisieren', + ru: 'Обновление версии прошивки на всех устройствах', + pt: 'Atualizar a versão de firmware em todos os dispositivos', + nl: 'Update firmaware versie op alle apparaten', + fr: 'Mettre à jour la version du firmware sur tous les appareils', + it: 'Aggiorna la versione firmware su tutti i dispositivi', + es: 'Actualizar la versión de firmware en todos los dispositivos', + pl: 'Oficjalna wersja oprogramowania', + uk: 'Оновлення версії прошивки на всіх пристроях', + 'zh-cn': '所有装置的更新软件版本', + }, + type: 'boolean', + role: 'button', + read: false, + write: true, + }, + native: {}, + }, + { + _id: 'info.downloadScripts', + type: 'state', + common: { + name: { + en: 'Download scripts from all devices', + de: 'Skripte von allen Geräten herunterladen', + ru: 'Скачать скрипты со всех устройств', + pt: 'Baixar scripts de todos os dispositivos', + nl: 'Download scripts van alle apparaten', + fr: 'Télécharger les scripts de tous les appareils', + it: 'Scarica gli script da tutti i dispositivi', + es: 'Descargar scripts de todos los dispositivos', + pl: 'Skrypty z wszystkich urządzeń', + uk: 'Завантажити скрипти з усіх пристроїв', + 'zh-cn': '所有装置的配件', + }, + type: 'boolean', + role: 'button', + read: false, + write: true, + }, + native: {}, + }, + { + _id: 'ble', + type: 'folder', + common: { + name: { + en: 'Bluetooth devices', + de: 'Bluetooth-Geräte', + ru: 'Bluetooth устройства', + pt: 'Dispositivos Bluetooth', + nl: 'Bluetooth apparatuur', + fr: 'Appareils Bluetooth', + it: 'Dispositivi Bluetooth', + es: 'Dispositivos Bluetooth', + pl: 'Bluetooth device', + uk: 'Пристрої Bluetooth', + 'zh-cn': '蓝图装置', + }, + desc: 'Help: https://github.com/iobroker-community-adapters/ioBroker.shelly/blob/master/docs/en/ble-devices.md', + }, + native: {}, + }, + ], + objects: [], + from: 'system.host.NanoPi-R5S.cli', + user: 'system.user.admin', + ts: 1726881156447, + }, + 'system.adapter.vis-2.0': { + _id: 'system.adapter.vis-2.0', + type: 'instance', + common: { + name: 'vis-2', + version: '2.9.64', + title: 'Visualisation Next Generation', + titleLang: { + en: 'Visualisation Next Generation', + de: 'Visualisierung Next Generation', + ru: 'Визуализация Next Generation', + pt: 'Visualização Next Generation', + nl: 'Visualisatie Next Generation', + fr: 'Visualisation Next Generation', + it: 'Visualizzazione Next Generation', + es: 'Visualización Next Generation', + pl: 'Wizualizacja Next Generation', + uk: 'Візуалізація Next Generation', + 'zh-cn': '可视化 Next Generation', + }, + desc: { + en: 'Extended GUI for ioBroker', + de: 'Erweiterte GUI für ioBroker', + ru: 'Расширенный GUI для ioBroker', + pt: 'GUI estendido para ioBroker', + nl: 'Uitgebreide GUI voor ioBroker', + fr: 'Interface graphique étendue pour ioBroker', + it: 'Interfaccia grafica estesa per ioBroker', + es: 'Interfaz gráfica extendida para ioBroker', + pl: 'Rozszerzone GUI dla ioBroker', + uk: 'Розширений GUI для ioBroker', + 'zh-cn': 'ioBroker的扩展GUI', + }, + platform: 'Javascript/Node.js', + loglevel: 'info', + icon: 'vis-2.png', + enabled: true, + mode: 'daemon', + nogit: true, + extIcon: 'https://raw.githubusercontent.com/iobroker/iobroker.vis-2/master/admin/vis-2.png', + keywords: ['DashUI', 'GUI', 'graphical', 'scada'], + messagebox: true, + readme: 'https://github.com/iobroker/iobroker.vis-2/blob/master/README.md', + authors: ['bluefox '], + localLinks: { + _default: '%web_protocol%://%ip%:%web_port%/vis-2/edit.html', + }, + license: 'CC-BY-NC-4.0', + dependencies: [ + { + web: '>=5.4.0', + }, + { + 'js-controller': '>=5.0.0', + }, + ], + restartAdapters: ['vis-2'], + serviceStates: 'lib/states.js', + singleton: true, + type: 'visualization', + connectionType: 'local', + dataSource: 'push', + tier: 3, + noConfig: false, + adminUI: { + config: 'json', + }, + compact: true, + materialize: true, + eraseOnUpload: true, + welcomeScreen: [ + { + link: 'vis-2/index.html', + name: 'vis 2 runtime', + img: 'vis-2/img/favicon.png', + color: '#ffe9c8', + order: 0, + }, + ], + welcomeScreenPro: [ + { + link: 'vis-2/edit.html', + name: 'vis 2 editor', + img: 'vis-2/img/faviconEdit.png', + color: '#c8ffe1', + order: 1, + }, + ], + stopBeforeUpdate: true, + installedFrom: 'iobroker.vis-2@2.9.64', + installedVersion: '2.9.64', + host: 'NanoPi-R5S', + plugins: { + sentry: { + dsn: 'https://db8b6e837c71447a876069559a00a742@sentry.iobroker.net/232', + }, + }, + licenseInformation: { + type: 'commercial', + link: 'https://github.com/ioBroker/ioBroker.vis-2?tab=readme-ov-file#license-requirements', + license: 'CC-BY-NC-4.0', + }, + }, + native: { + defaultFileMode: 1604, + license: '', + useLicenseManager: 0, + doNotShowProjectDialog: false, + loadingBackgroundColor: '', + loadingHideLogo: false, + loadingBackgroundImage: false, + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1726357236170, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: 'user files and images for vis-2', + type: 'meta.user', + }, + native: {}, + }, + { + _id: 'info', + type: 'channel', + common: { + name: 'info', + }, + native: {}, + }, + { + _id: 'info.uploaded', + type: 'state', + common: { + name: 'Files were uploaded', + type: 'number', + role: 'value.time', + }, + native: {}, + }, + { + _id: 'control', + type: 'channel', + common: { + name: 'Control vis-2', + }, + native: {}, + }, + { + _id: 'control.instance', + type: 'state', + common: { + name: 'Control vis-2', + type: 'string', + desc: "Write here browser instance ID to control or 'FFFFFFFF' to control all instances", + }, + native: {}, + }, + { + _id: 'control.command', + type: 'state', + common: { + name: 'Command for vis-2', + type: 'string', + desc: "Writing this variable act as the trigger. Instance and data must be preset before 'command' will be written. 'changedView' will be signalled too", + role: 'state', + states: { + alert: 'alert', + changeView: 'changeView', + refresh: 'refresh', + reload: 'reload', + dialog: 'dialog', + dialogClose: 'dialogClose', + popup: 'popup', + playSound: 'playSound', + changedView: 'changedView', + tts: 'tts', + }, + }, + native: {}, + }, + { + _id: 'control.data', + type: 'state', + common: { + name: 'Data for control vis-2', + type: 'string', + desc: 'Used for: alert, changeView, dialog, popup, playSound, changedView', + }, + native: {}, + }, + ], + objects: [], + }, + 'system.adapter.welcome.0': { + _id: 'system.adapter.welcome.0', + type: 'instance', + common: { + name: 'welcome', + version: '0.3.0', + title: 'Welcome page', + titleLang: { + en: 'Welcome page', + de: 'Willkommensseite', + ru: 'Страница: Добро пожаловать', + pt: 'Página de boas-vindas', + nl: 'Welkomstpagina', + fr: 'Page de bienvenue', + it: 'Pagina di benvenuto', + es: 'Página de bienvenida', + pl: 'Strona powitalna', + uk: 'Сторінка: Ласкаво просимо', + 'zh-cn': '欢迎页面', + }, + desc: { + en: 'Shows welcome page with list of ioBroker adapters with web servers', + de: 'Zeigt die Begrüßungsseite mit einer Liste der ioBroker-Adapter mit Webservern', + ru: 'Показывает приветственную страницу со списком адаптеров ioBroker с веб-серверами', + pt: 'Mostra a página de boas-vindas com a lista de adaptadores ioBroker com servidores da web', + nl: 'Toont welkomstpagina met lijst van ioBroker-adapters met webservers', + fr: 'Affiche la page de bienvenue avec la liste des adaptateurs ioBroker avec des serveurs Web', + it: "Mostra la pagina di benvenuto con l'elenco degli adattatori ioBroker con server Web", + es: 'Muestra la página de bienvenida con la lista de adaptadores ioBroker con servidores web', + pl: 'Pokazuje stronę powitalną z listą adapterów ioBroker z serwerami WWW', + uk: 'Показує сторінку вітання зі списком адаптерів ioBroker з веб-серверами', + 'zh-cn': '显示欢迎页面,其中包含ioBroker适配器列表和Web服务器', + }, + license: 'MIT', + mode: 'daemon', + platform: 'Javascript/Node.js', + loglevel: 'info', + icon: 'welcome.png', + readme: 'https://github.com/ioBroker/ioBroker.welcome/blob/master/README.md', + enabled: true, + compact: true, + nogit: true, + keywords: ['welcome', 'server', 'www', 'express'], + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.welcome/master/admin/welcome.png', + type: 'general', + adminUI: { + config: 'json', + }, + stopBeforeUpdate: true, + eraseOnUpload: true, + connectionType: 'local', + dataSource: 'push', + localLink: '%welcome_protocol%://%ip%:%welcome_port%/', + dependencies: [ + { + 'js-controller': '>=3.1.0', + }, + ], + globalDependencies: [ + { + admin: '>=5.1.0', + }, + ], + authors: [ + { + name: 'bluefox', + email: 'dogafox@gmail.com', + }, + ], + plugins: { + sentry: { + dsn: 'https://74bef31d2c6844cd85af54300b8a11bc@sentry.iobroker.net/243', + }, + }, + tier: 3, + installedFrom: 'iobroker.welcome@0.3.0', + installedVersion: '0.3.0', + host: 'NanoPi-R5S', + }, + native: { + allInstances: true, + specificInstances: [], + redirect: '', + port: 80, + auth: false, + secure: false, + bind: '0.0.0.0', + language: '', + defaultUser: 'admin', + welcomePhrase: 'Willkommen bei Talstraße 27', + backgroundColor: '', + backgroundToolbarColor: '', + retryInterval: 10, + customLinks: [], + redirectToLink: false, + redirectUrl: '', + }, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [], + instanceObjects: [ + { + _id: '', + type: 'meta', + common: { + name: 'user files and images for background image', + type: 'meta.user', + }, + native: {}, + }, + { + _id: 'info', + type: 'channel', + common: { + name: 'Information', + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + role: 'indicator.connected', + name: 'If web server started', + type: 'boolean', + read: true, + write: false, + def: false, + }, + native: {}, + }, + ], + objects: [], + from: 'system.host.NanoPi-R5S.cli', + user: 'system.user.admin', + ts: 1707381501646, + }, + 'system.adapter.ping.0': { + _id: 'system.adapter.ping.0', + type: 'instance', + common: { + name: 'ping', + version: '1.7.5', + titleLang: { + en: 'PING', + de: 'PING', + ru: 'PING', + pt: 'PING', + nl: 'PING', + fr: 'PING', + it: 'PING', + es: 'PING', + pl: 'PING', + uk: 'PING', + 'zh-cn': 'PING', + }, + desc: { + en: 'This adapter cyclic polls configured IPs.', + de: 'Adapter fragt zyklisch konfigurierte IP Addressen ab', + ru: 'Драйвер постоянно опрашивает заданные IP адреса при помощи утилиты PING', + pt: 'As pesquisas cíclicas deste adaptador configuraram IPs.', + nl: "Deze adapter cyclische polls geconfigureerde IP's.", + fr: 'Cet adaptateur interroge cycliquement les adresses IP configurées.', + it: 'Questo adattatore esegue il polling ciclico degli IP configurati.', + es: 'Este adaptador sondea cíclicamente las IP configuradas.', + pl: 'Ta karta cyklicznie odpytuje skonfigurowane adresy IP.', + uk: 'Цей адаптер циклічно опитує налаштовані IP-адреси.', + 'zh-cn': '该适配器循环轮询配置的IP。', + }, + authors: ['bluefox '], + platform: 'Javascript/Node.js', + mode: 'daemon', + compact: true, + readme: 'https://github.com/ioBroker/ioBroker.ping/blob/master/README.md', + loglevel: 'info', + icon: 'ping.png', + messagebox: true, + keywords: ['poll', 'ping', 'ip'], + adminUI: { + config: 'json', + }, + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.ping/master/admin/ping.png', + type: 'network', + plugins: { + sentry: { + dsn: 'https://2ac0bd290eda4f368ee03373392e2542@sentry.iobroker.net/34', + }, + }, + licenseInformation: { + type: 'free', + license: 'MIT', + }, + dependencies: [ + { + 'js-controller': '>=5.0.19', + }, + ], + connectionType: 'local', + dataSource: 'poll', + tier: 2, + installedFrom: 'iobroker.ping@1.7.5', + installedVersion: '1.7.5', + enabled: true, + host: 'NanoPi-R5S', + }, + native: { + devices: [], + interval: 60000, + intervalByUnreach: 30000, + numberOfRetries: 1, + noHostname: false, + autoDetect: '0', + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1726881127134, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: [], + encryptedNative: [], + notifications: [ + { + scope: 'ping', + name: { + en: 'ping', + de: 'ping', + ru: 'ping', + pt: 'ping', + nl: 'ping', + fr: 'ping', + it: 'ping', + es: 'ping', + pl: 'ping', + uk: 'ping', + 'zh-cn': 'ping', + }, + description: { + en: 'These notifications inform about new found devices.', + de: 'Diese Benachrichtigungen informieren über neu gefundene Geräte.', + ru: 'Эти уведомления информируют о новых найденных устройствах.', + pt: 'Essas notificações informam sobre novos dispositivos encontrados.', + nl: 'Deze meldingen informeren over nieuw gevonden apparaten.', + fr: 'Ces notifications informent sur les nouveaux appareils trouvés.', + it: 'Queste notifiche informano sui nuovi dispositivi trovati.', + es: 'Estas notificaciones informan sobre los nuevos dispositivos encontrados.', + pl: 'Te powiadomienia informują o nowo znalezionych urządzeniach.', + uk: 'Ці сповіщення інформують про нові знайдені пристрої.', + 'zh-cn': '这些通知通知您发现的新设备。', + }, + categories: [ + { + category: 'newDevices', + name: { + en: 'New IP addresses found', + de: 'Neue IP-Adressen gefunden', + ru: 'Найдены новые IP-адреса', + pt: 'Novos endereços IP encontrados', + nl: 'Nieuwe IP-adressen gevonden', + fr: 'Nouveaux adresses IP trouvées', + it: 'Nuovi indirizzi IP trovati', + es: 'Nuevas direcciones IP encontradas', + pl: 'Znaleziono nowe adresy IP', + uk: 'Знайдено нові IP-адреси', + 'zh-cn': '找到新的 IP 地址', + }, + severity: 'notify', + description: { + en: 'New IP addresses could be added for monitoring.', + de: 'Neue IP-Adressen könnten zur Überwachung hinzugefügt werden.', + ru: 'Новые IP-адреса могут быть добавлены для мониторинга.', + pt: 'Novos endereços IP podem ser adicionados para monitoramento.', + nl: 'Nieuwe IP-adressen kunnen worden toegevoegd voor monitoring.', + fr: 'De nouvelles adresses IP pourraient être ajoutées pour la surveillance.', + it: 'Nuovi indirizzi IP potrebbero essere aggiunti per il monitoraggio.', + es: 'Se podrían agregar nuevas direcciones IP para su monitoreo.', + pl: 'Nowe adresy IP mogą być dodane do monitorowania.', + uk: 'Нові IP-адреси можуть бути додані для моніторингу.', + 'zh-cn': '新的 IP 地址可以用于监控。', + }, + regex: [], + limit: 1, + }, + ], + }, + ], + instanceObjects: [ + { + _id: 'browse', + type: 'channel', + common: { + name: 'Browse', + }, + native: {}, + }, + { + _id: 'browse.progress', + type: 'state', + common: { + name: 'Progress', + type: 'number', + role: 'state', + read: true, + write: false, + def: 0, + min: 0, + max: 255, + }, + native: {}, + }, + { + _id: 'browse.result', + type: 'state', + common: { + name: 'Browse result', + type: 'json', + role: 'state', + read: true, + write: false, + def: '', + }, + native: {}, + }, + { + _id: 'browse.running', + type: 'state', + common: { + name: 'Browse running', + type: 'boolean', + role: 'state', + read: true, + write: true, + def: false, + }, + native: {}, + }, + { + _id: 'browse.status', + type: 'state', + common: { + name: 'Browse status', + type: 'string', + role: 'state', + read: true, + write: false, + def: '', + }, + native: {}, + }, + { + _id: 'browse.interface', + type: 'state', + common: { + name: 'Browse interface', + type: 'string', + role: 'state', + read: true, + write: true, + def: '', + }, + native: {}, + }, + { + _id: 'browse.rangeStart', + type: 'state', + common: { + name: 'Browse IP range start', + type: 'string', + role: 'state', + read: true, + write: true, + def: '', + }, + native: {}, + }, + { + _id: 'browse.rangeLength', + type: 'state', + common: { + name: 'Browse IP range length', + type: 'number', + role: 'state', + read: true, + write: true, + def: 0, + }, + native: {}, + }, + ], + objects: [], + user: 'system.user.admin', + }, + 'system.adapter.kisshome-research.0': { + common: { + name: 'kisshome-research', + version: '1.0.11', + titleLang: { + en: 'KISSHome research', + de: 'KISSHome-Forschung', + ru: 'Исследование KISSHome', + pt: 'Pesquisa KISSHome', + nl: 'KISSHome-onderzoek', + fr: 'Recherche KISSHome', + it: 'Ricerca KISSHome', + es: 'Investigación de KISSHome', + pl: 'Badania KISSHome', + uk: 'Дослідження KISSHome', + 'zh-cn': 'KISSHome研究', + }, + desc: { + en: 'Collection of information for KISSHome research', + de: 'Sammlung von Informationen für KISSHome-Forschung', + ru: 'Сбор информации для исследования KISSHome', + pt: 'Coleção de informações para pesquisa KISSHome', + nl: 'Verzameling informatie voor KISSHome-onderzoek', + fr: "Collection d'informations pour la recherche KISSHome", + it: 'Raccolta di informazioni per la ricerca KISSHome', + es: 'Colección de información para la investigación de KISSHome', + pl: 'Zbiór informacji do badań KISSHome', + uk: 'Збір інформації для дослідження KISSHome', + 'zh-cn': 'KISSHome研究信息收集', + }, + authors: ['Denis Haev '], + platform: 'Javascript/Node.js', + mode: 'daemon', + nogit: true, + loglevel: 'info', + readme: 'https://github.com/ioBroker/ioBroker.kisshome-research/blob/master/README.md', + icon: 'kisshome-research.png', + connectionType: 'local', + dataSource: 'push', + adminUI: { + config: 'json', + }, + tier: 3, + keywords: ['kisshome-research'], + stopTimeout: 5000, + enabled: true, + compact: true, + singletonHost: true, + extIcon: + 'https://raw.githubusercontent.com/ioBroker/ioBroker.kisshome-research/main/admin/kisshome-research.png', + type: 'utility', + messagebox: true, + plugins: { + sentry: { + dsn: 'https://10a9528535e3bbbf99f4282a20ff43d1@sentry.iobroker.net/248', + }, + }, + licenseInformation: { + type: 'free', + license: 'MIT', + }, + globalDependencies: [ + { + admin: '>=7.0.25', + }, + ], + installedFrom: 'iobroker.kisshome-research@1.0.11', + installedVersion: '1.0.11', + host: 'NanoPi-R5S', + }, + native: { + fritzbox: '192.168.178.1', + iface: '1-lan', + login: 'fritz6200', + password: '$/aes-192-cbc:84b5fcbb0b054d30e911134606f444c7:f021d1ee758d2b47dd459678f1270d7f', + tempDir: '', + devices: [ + { + ip: '192.168.178.74', + mac: 'B8:27:EB:A8:8A:82', + desc: 'hm-rpc', + enabled: true, + uuid: '81fa075e-3e0e-4e92-94e5-bbf55af3c518', + }, + { + ip: '192.168.178.108', + mac: '84:2E:14:FF:B0:8A', + desc: 'shelly', + enabled: true, + uuid: '00c65cbb-617f-4f30-af24-31ba64ee7f72', + }, + { + ip: '192.168.178.100', + desc: 'shelly', + enabled: true, + uuid: '22db03d3-308e-494d-a22b-8ce44d02b504', + }, + ], + email: 'max.mustermann@iobroker.com', + }, + type: 'instance', + instanceObjects: [ + { + _id: 'info', + type: 'device', + common: { + name: { + en: 'Information', + de: 'Informationen', + ru: 'Информация', + pt: 'Informação', + nl: 'Informatie', + fr: 'Information', + it: 'Informazioni', + es: 'Información', + pl: 'Informacja', + uk: 'Інформація', + 'zh-cn': '信息', + }, + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + name: { + en: 'Connected to FritzBox', + de: 'Verbindung mit FritzBox', + ru: 'Подключен к FritzBox', + pt: 'Conectado ao FritzBox', + nl: 'Verbinding met FritzBoxr', + fr: 'Connecté au FritzBox', + it: 'Collegato al FritzBox', + es: 'Conectado al FritzBox', + pl: 'Łączy się z FritzBox', + uk: 'Підключення до FritzBox', + 'zh-cn': 'Connected with FritzBox', + }, + type: 'boolean', + role: 'indicator.connected', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.recording', + type: 'channel', + common: { + name: { + en: 'Recoding on Fritz!Box', + de: 'Aufnahme auf Fritz!Box', + ru: 'Запись на Fritz!Box', + pt: 'Recoding no Fritz!Box', + nl: 'Opname op Fritz!Box', + fr: 'Enregistrement sur Fritz!Box', + it: 'Registrazione su Fritz!Box', + es: 'Grabación en Fritz!Box', + pl: 'Nagrywanie na Fritz!Box', + uk: 'Запис на Fritz!Box', + 'zh-cn': 'Fritz!Box上的录制', + }, + }, + native: {}, + }, + { + _id: 'info.recording.captured', + type: 'state', + common: { + name: { + en: 'How many packets captured after last start', + de: 'Wie viele Pakete wurden nach dem letzten Start erfasst', + ru: 'Сколько пакетов было захвачено после последнего запуска', + pt: 'Quantos pacotes foram capturados após a última inicialização', + nl: 'Hoeveel pakketten zijn er vastgelegd na de laatste start', + fr: 'Combien de paquets ont été capturés après le dernier démarrage', + it: "Quanti pacch, etti sono stati catturati dopo l'ultimo avvio", + es: 'Cuántos paquetes se capturaron después del último inicio', + pl: 'Ile pakietów zostało przechwyconych po ostatnim uruchomieniu', + uk: 'Скільки пакетів було захоплено після останнього запуску', + 'zh-cn': '上次启动后捕获了多少数据包', + }, + type: 'number', + role: 'state', + unit: 'packets', + read: true, + write: false, + def: 0, + }, + native: {}, + }, + { + _id: 'info.recording.enabled', + type: 'state', + common: { + name: { + en: 'Is recording is running', + de: 'Wird aufgezeichnet', + ru: 'Идет запись', + pt: 'A gravação está em execução', + nl: 'Wordt opgenomen', + fr: "L'enregistrement est en cours", + it: 'La registrazione è in corso', + es: 'La grabación está en curso', + pl: 'Nagrywanie jest w toku', + uk: 'Запис виконується', + 'zh-cn': '录制正在进行中', + }, + type: 'boolean', + role: 'state', + read: true, + write: true, + def: false, + }, + native: {}, + }, + { + _id: 'info.recording.running', + type: 'state', + common: { + name: { + en: 'Is recording is running', + de: 'Wird aufgezeichnet', + ru: 'Идет запись', + pt: 'A gravação está em execução', + nl: 'Wordt opgenomen', + fr: "L'enregistrement est en cours", + it: 'La registrazione è in corso', + es: 'La grabación está en curso', + pl: 'Nagrywanie jest w toku', + uk: 'Запис виконується', + 'zh-cn': '录制正在进行中', + }, + type: 'boolean', + role: 'state', + read: true, + write: true, + def: false, + }, + native: {}, + }, + { + _id: 'info.recording.triggerWrite', + type: 'state', + common: { + name: { + en: 'Triggers the creation of PCAP file', + de: 'Startet die Erstellung der PCAP-Datei', + ru: 'Запускает создание файла PCAP', + pt: 'Dispara a criação do arquivo PCAP', + nl: 'Start de creatie van het PCAP-bestand', + fr: 'Déclenche la création du fichier PCAP', + it: 'Avvia la creazione del file PCAP', + es: 'Desencadena la creación del archivo PCAP', + pl: 'Uruchamia tworzenie pliku PCAP', + uk: 'Запускає створення файлу PCAP', + 'zh-cn': '触发PCAP文件的创建', + }, + type: 'boolean', + role: 'state', + read: true, + write: true, + def: false, + }, + native: {}, + }, + { + _id: 'info.sync', + type: 'channel', + common: { + name: { + en: 'Synchronization with KISSHome', + de: 'Synchronisation mit KISSHome', + ru: 'Синхронизация с KISSHome', + pt: 'Sincronização com KISSHome', + nl: 'Synchronisatie met KISSHome', + fr: 'Synchronisation avec KISSHome', + it: 'Sincronizzazione con KISSHome', + es: 'Sincronización con KISSHome', + pl: 'Synchronizacja z KISSHome', + uk: 'Синхронізація з KISSHome', + 'zh-cn': '与KISSHome同步', + }, + }, + native: {}, + }, + { + _id: 'info.sync.running', + type: 'state', + common: { + name: { + en: 'RSync is running', + de: 'RSync läuft', + ru: 'RSync работает', + pt: 'RSync está em execução', + nl: 'RSync is aan het lopen', + fr: "RSync est en cours d'exécution", + it: 'RSync è in esecuzione', + es: 'RSync está corriendo', + pl: 'RSync działa', + uk: 'RSync працює', + 'zh-cn': 'RSync正在运行', + }, + type: 'boolean', + role: 'state', + read: true, + write: false, + def: false, + }, + native: {}, + }, + { + _id: 'info.sync.keys', + type: 'config', + common: { + name: { + en: 'Public and private keys', + de: 'Öffentliche und private Schlüssel', + ru: 'Публичные и частные ключи', + pt: 'Chaves públicas e privadas', + nl: 'Openbare en privésleutels', + fr: 'Clés publiques et privées', + it: 'Chiavi pubbliche e private', + es: 'Claves públicas y privadas', + pl: 'Klucze publiczne i prywatne', + uk: 'Публічні та приватні ключі', + 'zh-cn': '公钥和私钥', + }, + }, + native: { + publicKey: '', + privateKey: '', + }, + }, + ], + objects: [], + protectedNative: ['password', 'login'], + encryptedNative: ['password'], + notifications: [ + { + scope: 'kisshome-research', + name: { + en: 'KISSHome-Research', + de: 'KISSHome-Research', + ru: 'KISSHome-Research', + pt: 'KISSHome-Research', + nl: 'KISSHome-Research', + fr: 'KISSHome-Research', + it: 'KISSHome-Research', + es: 'KISSHome-Research', + pl: 'KISSHome-Research', + uk: 'KISSHome-Research', + 'zh-cn': 'KISSHome-Research', + }, + description: { + en: 'Problem with KISSHome-Research instance', + de: 'Problem mit KISSHome-Research-Instanz', + ru: 'Проблема с экземпляром KISSHome-Research', + pt: 'Problema com a instância KISSHome-Research', + nl: 'Probleem met KISSHome-Research-instantie', + fr: "Problème avec l'instance KISSHome-Research", + it: "Problema con l'istanza KISSHome-Research", + es: 'Problema con la instancia KISSHome-Research', + pl: 'Problem z instancją KISSHome-Research', + uk: 'Проблема з екземпляром KISSHome-Research', + 'zh-cn': 'KISSHome-Research 实例存在问题', + }, + categories: [ + { + category: 'publicKey', + name: { + en: 'Problem with KISSHome-Research instance', + de: 'Problem mit KISSHome-Research-Instanz', + ru: 'Проблема с экземпляром KISSHome-Research', + pt: 'Problema com a instância KISSHome-Research', + nl: 'Probleem met KISSHome-Research-instantie', + fr: "Problème avec l'instance KISSHome-Research", + it: "Problema con l'istanza KISSHome-Research", + es: 'Problema con la instancia KISSHome-Research', + pl: 'Problem z instancją KISSHome-Research', + uk: 'Проблема з екземпляром KISSHome-Research', + 'zh-cn': 'KISSHome-Research 实例存在问题', + }, + severity: 'notify', + description: { + en: 'The public key was rejected because previous connections used a different one. It can happens, if your settings for instance was deleted and then the instance was created again. To make the acceptance of the new public key possible, please contact us under kisshome@internet-sicherheit.de and provide the reason why the public key was changed.', + de: 'Der Public-Schlüssel wurde abgelehnt, da frühere Verbindungen einen anderen verwendeten. Es kann vorkommen, wenn Ihre Einstellungen für die Instanz gelöscht wurden und dann die Instanz erneut erstellt wurde. Um die Annahme des neuen öffentlichen Schlüssels zu ermöglichen, kontaktieren Sie uns bitte unter kisshome@internet-sicherheit.de und geben Sie den Grund an, warum der öffentliche Schlüssel geändert wurde.', + ru: 'Публичный ключ был отклонен, потому что предыдущие подключения использовали другой. Это может произойти, если ваши настройки для экземпляра были удалены, а затем экземпляр был создан снова. Чтобы сделать возможным принятие нового открытого ключа, пожалуйста, свяжитесь с нами по адресу kisshome@internet-sicherheit.de и укажите причину изменения открытого ключа.', + pt: 'A chave pública foi rejeitada porque as conexões anteriores usaram uma diferente. Pode acontecer se suas configurações para a instância foram excluídas e, em seguida, a instância foi criada novamente. Para tornar possível a aceitação da nova chave pública, entre em contato conosco em kisshome@internet-sicherheit.de e forneça o motivo da alteração da chave pública.', + nl: 'De openbare sleutel werd afgewezen omdat eerdere verbindingen een andere gebruikten. Het kan gebeuren als uw instellingen voor de instantie zijn verwijderd en vervolgens de instantie opnieuw is gemaakt. Om de acceptatie van de nieuwe openbare sleutel mogelijk te maken, neem contact met ons op via kisshome@internet-sicherheit.de en geef de reden op waarom de openbare sleutel is gewijzigd.', + fr: "La clé publique a été rejetée car les connexions précédentes utilisaient une autre clé. Cela peut se produire si vos paramètres pour l'instance ont été supprimés, puis que l'instance a été recréée. Pour rendre possible l'acceptation de la nouvelle clé publique, veuillez nous contacter à kisshome@internet-sicherheit.de et fournir la raison pour laquelle la clé publique a été modifiée.", + it: "La chiave pubblica è stata rifiutata perché le connessioni precedenti ne utilizzavano una diversa. Può accadere se le impostazioni per l'istanza sono state eliminate e quindi l'istanza è stata creata nuovamente. Per rendere possibile l'accettazione del nuovo chiave pubblica, contattaci a kisshome@internet-sicherheit.de e fornisci il motivo per cui la chiave pubblica è stata modificata.", + es: 'La clave pública fue rechazada porque las conexiones anteriores usaban una diferente. Puede suceder si su configuración para la instancia fue eliminada y luego la instancia fue creada nuevamente. Para hacer posible la aceptación de la nueva clave pública, contáctenos en kisshome@internet-sicherheit.de y proporcione la razón por la que se cambió la clave pública.', + pl: 'Klucz publiczny został odrzucony, ponieważ poprzednie połączenia używały innego. Może się zdarzyć, jeśli Twoje ustawienia dla instancji zostały usunięte, a następnie instancja została utworzona ponownie. Aby umożliwić akceptację nowego klucza publicznego, skontaktuj się z nami pod adresem kisshome@internet-sicherheit.de i podaj powód zmiany klucza publicznego.', + uk: "Відкритий ключ був відхилений, оскільки попередні підключення використовували інший. Це може статися, якщо ваші налаштування для екземпляра були видалені, а потім екземпляр був створений знову. Щоб зробити прийняття нового відкритого ключа можливим, будь ласка, зв'яжіться з нами за адресою kisshome@internet-sicherheit.de і вкажіть причину зміни відкритого ключа.", + 'zh-cn': + '公钥被拒绝,因为之前的连接使用了不同的公钥. 如果您的实例设置被删除,然后实例被重新创建,就会发生这种情况。为了使新公钥的接受成为可能,请通过 kisshome@internet-sicherheit.de 与我们联系,并提供更改公钥的原因。', + }, + regex: [], + limit: 1, + }, + ], + }, + ], + _id: 'system.adapter.kisshome-research.0', + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + from: 'system.adapter.admin.0', + user: 'system.user.admin', + ts: 1727347686966, + }, + 'system.adapter.node-red.0': { + _id: 'system.adapter.node-red.0', + type: 'instance', + common: { + name: 'node-red', + version: '5.2.1', + titleLang: { + en: 'Node-RED', + de: 'Node-RED', + ru: 'Node-RED', + pt: 'Node-RED', + nl: 'Node-RED', + fr: 'Node-RED', + it: 'Node-RED', + es: 'Node-RED', + pl: 'Node-RED', + uk: 'Node-RED', + 'zh-cn': 'Node-RED', + }, + desc: { + en: 'This adapter uses node-red as a service. No additional node-red instance required.', + de: 'Adapter benutzt node-red als Service. Kein zusätzliches node-red Programm nötig.', + ru: 'Драйвер создает node-red сервер и позволяет общаться с ним.', + pt: 'Este adaptador usa node-red como um serviço. Nenhuma instância node-red adicional é necessária.', + nl: 'Deze adapter gebruikt node-red als een service. Geen extra node-red exemplaar vereist.', + fr: 'Cet adaptateur utilise node-red en tant que service. Aucune instance node-red supplémentaire requise.', + it: 'Questo adattatore utilizza node-red come servizio. Nessuna istanza aggiuntiva node-red richiesta.', + es: 'Este adaptador usa node-red como un servicio. No se requiere ninguna instancia adicional de node-red.', + pl: 'Ten adapter używa node-red jako usługi. Żadna dodatkowa instancja node-red nie jest wymagana.', + uk: 'Цей адаптер використовує node-red як службу. Додатковий екземпляр node-red не потрібен.', + 'zh-cn': '此适配器将node-red作为服务, 不需要额外安装node-red实例.', + }, + authors: [ + 'bluefox ', + 'Matthias Kleine ', + 'Ingo Fischer ', + ], + licenseInformation: { + license: 'Apache-2.0', + type: 'free', + }, + platform: 'Javascript/Node.js', + mode: 'daemon', + messagebox: true, + loglevel: 'info', + icon: 'node-red.png', + keywords: ['node-red', 'logic', 'script'], + extIcon: 'https://raw.githubusercontent.com/ioBroker/ioBroker.node-red/master/admin/node-red.png', + localLinks: { + _default: { + link: 'http%s%://%ip%:%port%%httpAdminRoot%', + }, + }, + docs: { + en: ['docs/en/README.md'], + de: ['docs/de/README.md'], + }, + enabled: true, + supportStopInstance: 5000, + unsafePerm: true, + compact: true, + type: 'logic', + readme: 'https://github.com/ioBroker/ioBroker.node-red/blob/master/README.md', + stopBeforeUpdate: true, + adminTab: { + link: '%protocol%://%ip%:%port%%httpAdminRoot%', + name: { + en: 'Node-RED', + de: 'Node-RED', + ru: 'Node-RED', + pt: 'Node-RED', + nl: 'Node-RED', + fr: 'Node-RED', + it: 'Node-RED', + es: 'Node-RED', + pl: 'Node-RED', + uk: 'Node-RED', + 'zh-cn': 'Node-RED', + }, + singleton: false, + 'fa-icon': 'settings_input_composite', + }, + adminUI: { + config: 'json', + tab: 'html', + }, + dependencies: [ + { + 'js-controller': '>=3.3.22', + }, + ], + globalDependencies: [ + { + admin: '>=6.0.0', + }, + ], + tier: 1, + connectionType: 'local', + dataSource: 'push', + messages: [ + { + condition: { + operand: 'and', + rules: ['oldVersion<3.0.0', 'newVersion>=3.0.0'], + }, + title: { + en: 'Node-red upgraded to 2.x', + de: 'Node-Red auf 2.x aktualisiert', + ru: 'Node-red обновлен до версии 2.x', + pt: 'Node-red atualizado para 2.x', + nl: 'Node-rood geüpgraded naar 2.x', + fr: 'Node-red mis à niveau vers 2.x', + it: 'Node-red aggiornato a 2.x', + es: 'Nodo-rojo actualizado a 2.x', + pl: 'Węzeł-czerwony uaktualniony do 2.x', + uk: 'Node-red оновлено до 2.x', + 'zh-cn': 'Node-red升级到2.x', + }, + text: { + en: 'This adapter upgrade includes an upgrade of Node-RED to v2. Please check your nodes for compatibility! See also the adapter changelog, https://nodered.org/blog/2021/07/20/version-2-0-released and https://nodered.org/blog/2021/10/21/version-2-1-released and https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + de: 'Dieses Adapter-Upgrade beinhaltet ein Upgrade von Node-RED auf v2. Bitte prüfen Sie Ihre Nodes auf Kompatibilität! Siehe auch Adapter Changelog, https://nodered.org/blog/2021/07/20/version-2-0-released und https://nodered.org/blog/2021/10/21/version-2- 1-freigegeben und https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + ru: 'Это обновление адаптера включает в себя обновление Node-RED до v2. Пожалуйста, проверьте ваши узлы на совместимость! См. также журнал изменений адаптера, https://nodered.org/blog/2021/07/20/version-2-0-released и https://nodered.org/blog/2021/10/21/version-2-. 1-релиз и https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + pt: 'Esta atualização do adaptador inclui uma atualização do Node-RED para v2. Verifique a compatibilidade de seus nós! Consulte também o log de alterações do adaptador, https://nodered.org/blog/2021/07/20/version-2-0-released e https://nodered.org/blog/2021/10/21/version-2- 1-lançado e https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + nl: 'Deze adapter-upgrade omvat een upgrade van Node-RED naar v2. Controleer uw nodes op compatibiliteit! Zie ook de adapter changelog, https://nodered.org/blog/2021/07/20/version-2-0-released en https://nodered.org/blog/2021/10/21/version-2- 1-released en https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + fr: "Cette mise à niveau de l'adaptateur inclut une mise à niveau de Node-RED vers v2. Veuillez vérifier la compatibilité de vos nœuds ! Voir aussi le changelog de l'adaptateur, https://nodered.org/blog/2021/07/20/version-2-0-released et https://nodered.org/blog/2021/10/21/version-2- 1-publié et https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository", + it: "Questo aggiornamento dell'adattatore include un aggiornamento di Node-RED alla v2. Controlla la compatibilità dei tuoi nodi! Vedi anche il log delle modifiche dell'adattatore, https://nodered.org/blog/2021/07/20/version-2-0-released e https://nodered.org/blog/2021/10/21/version-2- 1-rilasciato e https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository", + es: 'Esta actualización del adaptador incluye una actualización de Node-RED a v2. ¡Compruebe la compatibilidad de sus nodos! Consulte también el registro de cambios del adaptador, https://nodered.org/blog/2021/07/20/version-2-0-released y https://nodered.org/blog/2021/10/21/version-2- 1-lanzado y https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + pl: 'To uaktualnienie adaptera obejmuje aktualizację Node-RED do wersji 2. Sprawdź swoje węzły pod kątem kompatybilności! Zobacz także dziennik zmian adaptera, https://nodered.org/blog/2021/07/20/version-2-0-released i https://nodered.org/blog/2021/10/21/version-2- 1-wydany i https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + uk: 'Це оновлення адаптера включає оновлення Node-RED до v2. Будь ласка, перевірте свої вузли на сумісність! Перегляньте також журнал змін адаптера, https://nodered.org/blog/2021/07/20/version-2-0-released і https://nodered.org/blog/2021/10/21/version-2- 1-випущено та https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + 'zh-cn': + '此适配器升级包括将 Node-RED 升级到 v2。请检查您的节点是否兼容!另请参阅适配器更改日志,https://nodered.org/blog/2021/07/20/version-2-0-released 和 https://nodered.org/blog/2021/10/21/version-2- 1-发布和 https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + }, + link: 'https://forum.iobroker.net/topic/53300/neuer-node-red-adapter-3-x-in-latest-repository', + level: 'warn', + linkText: { + en: 'Forum-Thread (German)', + de: 'Forum-Thread', + ru: 'Тема форума (немецкий)', + pt: 'Fórum-Tópico (alemão)', + nl: 'Forum-Thread (Duits)', + fr: 'Fil de discussion du forum (allemand)', + it: 'Forum-Thread (tedesco)', + es: 'Tema del foro (alemán)', + pl: 'Forum-wątek (niemiecki)', + uk: 'Тема форуму (німецька)', + 'zh-cn': '论坛主题(德语)', + }, + buttons: ['agree', 'cancel'], + }, + { + condition: { + operand: 'and', + rules: ['oldVersion<5.0.0', 'newVersion>=5.0.0'], + }, + title: { + en: 'Adapter has been migrated to Admin 6 configuration', + de: 'Adapter wurde auf Admin 6 Konfiguration migriert', + ru: 'Адаптер был мигрирован до конфигурации Admin 6', + pt: 'Adapter foi migrado para configuração Admin 6', + nl: 'Adapter is gemigreerd tot administratie 6', + fr: 'Adaptateur a été migré vers la configuration Admin 6', + it: "L'adattatore è stato migrato alla configurazione Admin 6", + es: 'Adaptador ha sido migrado a la configuración Admin 6', + pl: 'Adapter przeniesiono do Admin 6', + uk: 'Адаптер мігрований до конфігурації Admin 6', + 'zh-cn': '已移到“6种组合”', + }, + text: { + en: 'Please check instance configuration and re-enter your passwords (encryption has changed).', + de: 'Bitte überprüfen Sie die Instanzkonfiguration und geben Sie Ihre Passwörter erneut ein (Verschlüsselung hat sich geändert).', + ru: 'Пожалуйста, проверьте настройки и повторно введите свои пароли (шифрование изменилось).', + pt: 'Por favor, verifique a configuração da instância e reinsira suas senhas (a criptografia mudou).', + nl: 'Controleer instanceconfiguratie en verbind uw wachtwoorden.', + fr: "Veuillez vérifier la configuration de l'instance et réactiver vos mots de passe (le chiffrement a changé).", + it: 'Si prega di controllare la configurazione delle istanze e ri-inserire le password (la crittografia è cambiata).', + es: 'Por favor, compruebe la configuración de instancia y vuelva a introducir sus contraseñas (el cifrado ha cambiado).', + pl: 'Pozwoliło się na skonfigurowanie instancji i ponowne wejście do haseł (wyszyfrowanie zmieniło się).', + uk: 'Будь ласка, перевірте налаштування екземпляра та перейменуйте ваші паролі.', + 'zh-cn': '请核对表和重新编号(加密已改变)。.', + }, + link: 'https://github.com/ioBroker/ioBroker.node-red/blob/master/docs/en/README.md', + level: 'warn', + linkText: { + en: 'Documentation', + de: 'Dokumentation', + ru: 'Документация', + pt: 'Documentação', + nl: 'Document', + fr: 'Documentation', + it: 'Documentazione', + es: 'Documentación', + pl: 'Dokumentacja', + uk: 'Документація', + 'zh-cn': '文件', + }, + buttons: ['agree', 'cancel'], + }, + ], + installedFrom: 'iobroker.node-red@5.2.1', + installedVersion: '5.2.1', + host: 'NanoPi-R5S', + }, + native: { + bind: '0.0.0.0', + port: 1880, + secure: false, + certPublic: '', + certPrivate: '', + httpAdminRoot: '/', + httpNodeRoot: '', + httpStatic: '', + npmLibs: [], + maxMemory: 128, + valueConvert: false, + palletmanagerEnabled: false, + projectsEnabled: false, + allowCreationOfForeignObjects: false, + safeMode: false, + doNotReadObjectsDynamically: false, + authType: 'None', + user: '', + pass: '', + hasDefaultPermissions: false, + defaultPermissions: '', + authExt: [], + editor: 'monaco', + theme: '', + envVars: [], + }, + from: 'system.host.NanoPi-R5S.cli', + ts: 1727600423360, + acl: { + object: 1636, + owner: 'system.user.admin', + ownerGroup: 'system.group.administrator', + }, + protectedNative: ['user', 'pass'], + encryptedNative: ['pass'], + notifications: [], + instanceObjects: [ + { + _id: 'info', + type: 'channel', + common: { + name: { + en: 'Information', + de: 'Information', + ru: 'Информация', + pt: 'Em formação', + nl: 'Informatie', + fr: 'Informations', + it: 'Informazione', + es: 'Información', + pl: 'Informacja', + uk: 'Інформація', + 'zh-cn': '信息', + }, + }, + native: {}, + }, + { + _id: 'info.connection', + type: 'state', + common: { + name: { + en: 'Process is running', + de: 'Prozess läuft', + ru: 'Процесс работает', + pt: 'O processo está em execução', + nl: 'Proces loopt', + fr: 'Le processus est en cours', + it: 'Il processo è in esecuzione', + es: 'El proceso está en marcha', + pl: 'Proces', + uk: 'Процес працює', + 'zh-cn': '进程', + }, + type: 'boolean', + role: 'indicator.reachable', + read: true, + write: false, + def: false, + }, + native: {}, + }, + ], + objects: [], + }, +}; + +const hosts = { + 'system.host.demoPC': { + _id: 'system.host.demoPC', + common: { + name: 'demoPC', + installedVersion: '6.0.11', + }, + native: { + hardware: { + networkInterfaces: { + lo: [ + { + address: '127.0.0.1', + netmask: '255.0.0.0', + family: 'IPv4', + mac: '00:00:00:00:00:00', + internal: true, + cidr: '127.0.0.1/8', + }, + { + address: '::1', + netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', + family: 'IPv6', + mac: '00:00:00:00:00:00', + internal: true, + cidr: '::1/128', + scopeid: 0, + }, + ], + eth0: [ + { + address: '192.168.178.2', + netmask: '255.255.255.0', + family: 'IPv4', + mac: '12:23:34:56:54:34', + internal: false, + cidr: '192.168.178.2/24', + }, + { + address: 'fd7a:1234:1234:1234:1234:1234:1234:1234', + netmask: 'ffff:ffff:ffff:ffff::', + family: 'IPv6', + mac: '12:23:34:56:54:34', + internal: false, + cidr: 'fd7a:1234:1234:1234:1234:1234:1234:1234/64', + scopeid: 0, + }, + { + address: 'fe80::2342:1234:4567:1234', + netmask: 'ffff:ffff:ffff:ffff::', + family: 'IPv6', + mac: '12:23:34:56:54:34', + internal: false, + cidr: 'fe80::2342:1234:4567:1234/64', + scopeid: 2, + }, + ], + tailscale0: [ + { + address: '123.123.123.123', + netmask: '255.255.255.255', + family: 'IPv4', + mac: '00:00:00:00:00:00', + internal: false, + cidr: '123.123.123.123/32', + }, + { + address: 'fd7a:1234:1234:1234:1234:1234:1234:1234', + netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', + family: 'IPv6', + mac: '00:00:00:00:00:00', + internal: false, + cidr: 'fd7a:1234:1234:1234:1234:1234:1234:1234/128', + scopeid: 0, + }, + { + address: 'fe80::2342:1234:4567:1234', + netmask: 'ffff:ffff:ffff:ffff::', + family: 'IPv6', + mac: '00:00:00:00:00:00', + internal: false, + cidr: 'fe80::2342:1234:4567:1234/64', + scopeid: 5, + }, + ], + }, + }, + }, + }, +}; + +describe('Test replace link in front-end', function () { + it('welcome', function (done) { + const link = 'http%s%://%ip%:%port%%httpAdminRoot%'; + const name = 'node-red'; + const instanceId = 0; + const hostname = '123.456.789.123'; + const adminInstance = 'admin.0'; + const result = replaceLink(link, name, instanceId, { + instances, + hostname, + adminInstance, + hosts, + }); + + expect(result.length).to.be.equal(1); + expect(result[0].url).to.be.equal('http://123.456.789.123:1880/'); + expect(result[0].port).to.be.equal(1880); + + done(); + }); +}); diff --git a/packages/admin/tsconfig.json b/packages/admin/tsconfig.json index cc7a20497..a3fb65a67 100644 --- a/packages/admin/tsconfig.json +++ b/packages/admin/tsconfig.json @@ -8,6 +8,8 @@ "allowJs": true, "checkJs": true, "outDir": "./build-backend/", + "sourceMap": true, + "inlineSources": true, // This is necessary for the automatic typing of the adapter config "resolveJsonModule": true, diff --git a/packages/dm-gui-components/package.json b/packages/dm-gui-components/package.json index 4a4a31be4..f7931ce45 100644 --- a/packages/dm-gui-components/package.json +++ b/packages/dm-gui-components/package.json @@ -1,6 +1,6 @@ { "name": "@iobroker/dm-gui-components", - "version": "7.1.5", + "version": "7.2.0", "description": "ReactJS components to develop admin interface for ioBroker device manager.", "author": { "name": "Jey Cee", @@ -48,7 +48,7 @@ }, "homepage": "https://github.com/ioBroker/dm-gui-components#readme", "dependencies": { - "@iobroker/adapter-react-v5": "^7.1.4", + "@iobroker/adapter-react-v5": "^7.2.1", "@iobroker/json-config": "file:../jsonConfig" } } diff --git a/packages/dm-gui-components/tsconfig.json b/packages/dm-gui-components/tsconfig.json index df8aab34a..2c0fc35ab 100644 --- a/packages/dm-gui-components/tsconfig.json +++ b/packages/dm-gui-components/tsconfig.json @@ -11,6 +11,7 @@ "declaration": true, "outDir": "./build", "sourceMap": true, + "inlineSources": true, "sourceRoot": "./src", "noImplicitAny": true, "skipLibCheck": true, diff --git a/packages/jsonConfig/package.json b/packages/jsonConfig/package.json index 33d7b7e54..b118d8b27 100644 --- a/packages/jsonConfig/package.json +++ b/packages/jsonConfig/package.json @@ -1,7 +1,7 @@ { "name": "@iobroker/json-config", "description": "This package contains the ioBroker JSON config UI components", - "version": "7.1.5", + "version": "7.2.0", "main": "./build/index.js", "types": "./build/index.d.ts", "scripts": { @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@iobroker/adapter-react-v5": "^7.1.4", + "@iobroker/adapter-react-v5": "^7.2.1", "crypto-js": "^4.2.0", "react-ace": "^12.0.0" }, diff --git a/packages/jsonConfig/tsconfig.json b/packages/jsonConfig/tsconfig.json index c168d479b..a20c7b55c 100644 --- a/packages/jsonConfig/tsconfig.json +++ b/packages/jsonConfig/tsconfig.json @@ -7,9 +7,10 @@ "checkJs": false, "noEmit": false, "declaration": true, + "sourceMap": true, + "inlineSources": true, "outDir": "./build", "baseUrl": "./", - "sourceMap": true, "sourceRoot": "./src", "noImplicitAny": true, "skipLibCheck": true,