diff --git a/.github/auto-merge.yml b/.github/auto-merge.yml new file mode 100644 index 0000000..3f5fbe3 --- /dev/null +++ b/.github/auto-merge.yml @@ -0,0 +1,17 @@ +# Configure here which dependency updates should be merged automatically. +# The recommended configuration is the following: +- match: + # Only merge patches for production dependencies + dependency_type: production + update_type: "semver:patch" +- match: + # Except for security fixes, here we allow minor patches + dependency_type: production + update_type: "security:minor" +- match: + # and development dependencies can have a minor update, too + dependency_type: development + update_type: "semver:minor" + +# The syntax is based on the legacy dependabot v1 automerged_updates syntax, see: +# https://dependabot.com/docs/config-file/#automerged_updates \ No newline at end of file diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml new file mode 100644 index 0000000..310f4a0 --- /dev/null +++ b/.github/workflows/dependabot-automerge.yml @@ -0,0 +1,22 @@ +# Automatically merge Dependabot PRs when version comparison is within the range +# that is configured in .github/auto-merge.yml + +name: Auto-Merge Dependabot PRs + +on: + pull_request_target: + +jobs: + auto-merge: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Check if PR should be auto-merged + uses: ahmadnassri/action-dependabot-auto-merge@v2 + with: + # This must be a personal access token with push access + github-token: ${{ secrets.AUTO_MERGE_TOKEN }} + # By default, squash and merge, so Github chooses nice commit messages + command: squash and merge \ No newline at end of file diff --git a/README.md b/README.md index 9260f21..44ace40 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,9 @@ This adapter uses the node-red server from https://github.com/node-red/node-red ## Changelog ### __WORK IN PROGRESS__ -* (Apollon77) Add done calls to some nodes +* (Apollon77) BREAKING update from node-red-contrib-aggregator: topic is NOT converted to lowercase anymore! +* (Apollon77) update to node-red 1.3.2 +* (Apollon77) Add done calls to OutNode ### 2.2.0 (2021-03-07) * (Apollon77/mickym2) Correct readonly flags. IMPORTANT: Notw Readonly works as it should be. If you worked around the issue before please adjust your nodes! diff --git a/admin/i18n/de/translations.json b/admin/i18n/de/translations.json new file mode 100644 index 0000000..0acb5ec --- /dev/null +++ b/admin/i18n/de/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Modul hinzufügen", + "Additional npm modules:": "Zusätzliche NPM-Module", + "Allow creation of foreign objects": "Erstellung von Fremd-Objekten zulassen", + "Backups will not contain any projects or modules installed via the Palletmanager": "Backups enthalten keine Projekte und auch keine Module die mit dem Palletenmanager installiert sind.", + "Convert values to string:": "ioBroker-Werte in String konvertieren:", + "Divided by comma": "Getrennt mit Komma", + "Enable Projects Feature:": "Projektfunktion aktivieren", + "Leave blank to disable basic authentication": "Leer lassen, um die Basic-Authentication zu deaktivieren", + "Max allocated RAM:": "Max zugewiesener RAM", + "Module names": "Modulnamen", + "Password": "Passwort", + "Safe mode": "Sicherheitsmodus", + "Update select dialog": "Update Dialog um ID zu selektieren", + "Use palletmanager:": "Palletenmanager benutzen", + "User": "Benutzer", + "Web server port:": "Web-Server-Port", + "http root directory:": "http Stammpfad", + "node-red settings": "node-red Einstellungen", + "node-red update select dialog": "node-red SelectID Dialog aktualisieren" +} \ No newline at end of file diff --git a/admin/i18n/en/translations.json b/admin/i18n/en/translations.json new file mode 100644 index 0000000..59b5e38 --- /dev/null +++ b/admin/i18n/en/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Add module", + "Additional npm modules:": "Additional npm modules", + "Allow creation of foreign objects": "Allow creation of foreign objects", + "Backups will not contain any projects or modules installed via the Palletmanager": "Backups will not contain any projects or modules installed via the Palletmanager!", + "Convert values to string:": "Convert ioBroker values to string", + "Divided by comma": "Divided by comma", + "Enable Projects Feature:": "Enable Projects Feature", + "Leave blank to disable basic authentication": "Leave blank to disable basic authentication", + "Max allocated RAM:": "Max allocated RAM", + "Module names": "Module names", + "Password": "Password", + "Safe mode": "Safe mode", + "Update select dialog": "Update select dialog", + "Use palletmanager:": "Use palletmanager", + "User": "User", + "Web server port:": "Web server port", + "http root directory:": "http root directory", + "node-red settings": "node-red settings", + "node-red update select dialog": "node-red update select dialog" +} \ No newline at end of file diff --git a/admin/i18n/es/translations.json b/admin/i18n/es/translations.json new file mode 100644 index 0000000..58b4b2e --- /dev/null +++ b/admin/i18n/es/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Agregar módulo", + "Additional npm modules:": "Módulos npm adicionales", + "Allow creation of foreign objects": "Permitir la creación de objetos extraños.", + "Backups will not contain any projects or modules installed via the Palletmanager": "¡Las copias de seguridad no contendrán ningún proyecto o módulo instalado a través del Palletmanager!", + "Convert values to string:": "Convierta los valores de ioBroker en una cadena", + "Divided by comma": "Dividido por coma", + "Enable Projects Feature:": "Habilitar característica de proyectos", + "Leave blank to disable basic authentication": "Dejar en blanco para deshabilitar la autenticación básica", + "Max allocated RAM:": "RAM máxima asignada", + "Module names": "Nombres de módulos", + "Password": "Contraseña", + "Safe mode": "Modo seguro", + "Update select dialog": "Actualizar diálogo de selección", + "Use palletmanager:": "Utilice palletmanager", + "User": "Usuario", + "Web server port:": "Puerto del servidor web", + "http root directory:": "directorio raíz http", + "node-red settings": "configuración de node-red", + "node-red update select dialog": "diálogo de selección de actualización node-red" +} \ No newline at end of file diff --git a/admin/i18n/fr/translations.json b/admin/i18n/fr/translations.json new file mode 100644 index 0000000..86a3c4d --- /dev/null +++ b/admin/i18n/fr/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Ajouter un module", + "Additional npm modules:": "Modules NPM supplémentaires", + "Allow creation of foreign objects": "Autoriser la création d'objets étrangers", + "Backups will not contain any projects or modules installed via the Palletmanager": "Les sauvegardes ne contiendront aucun projet ou module installé via le Palletmanager!", + "Convert values to string:": "Convertir les valeurs de ioBroker en chaîne", + "Divided by comma": "Divisé par une virgule", + "Enable Projects Feature:": "Activer la fonctionnalité de projets", + "Leave blank to disable basic authentication": "Laissez vide pour désactiver l'authentification de base", + "Max allocated RAM:": "Max allouée RAM", + "Module names": "Noms de modules", + "Password": "Mot de passe", + "Safe mode": "Mode sans échec", + "Update select dialog": "Mettre à jour le dialogue", + "Use palletmanager:": "Utiliser Palletmanager", + "User": "Utilisateur", + "Web server port:": "Port du serveur Web", + "http root directory:": "répertoire racine http", + "node-red settings": "paramètres de node-red", + "node-red update select dialog": "boîte de dialogue de sélection de mise à jour de noeud" +} \ No newline at end of file diff --git a/admin/i18n/it/translations.json b/admin/i18n/it/translations.json new file mode 100644 index 0000000..212fe4b --- /dev/null +++ b/admin/i18n/it/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Aggiungi modulo", + "Additional npm modules:": "Ulteriori moduli npm", + "Allow creation of foreign objects": "Consentire la creazione di oggetti estranei", + "Backups will not contain any projects or modules installed via the Palletmanager": "I backup non conterranno progetti o moduli installati tramite Palletmanager!", + "Convert values to string:": "Converti i valori di ioBroker in stringa", + "Divided by comma": "Diviso in virgola", + "Enable Projects Feature:": "Abilita funzionalità progetti", + "Leave blank to disable basic authentication": "Lascia vuoto per disabilitare l'autenticazione di base", + "Max allocated RAM:": "RAM allocata massima", + "Module names": "Nomi dei moduli", + "Password": "Parola d'ordine", + "Safe mode": "Modalità sicura", + "Update select dialog": "Aggiorna la finestra di selezione", + "Use palletmanager:": "Usa palletmanager", + "User": "Utente", + "Web server port:": "Porta del server Web", + "http root directory:": "directory root http", + "node-red settings": "impostazioni del node-red", + "node-red update select dialog": "finestra di dialogo di selezione aggiornamento node-red" +} \ No newline at end of file diff --git a/admin/i18n/nl/translations.json b/admin/i18n/nl/translations.json new file mode 100644 index 0000000..3dccfa7 --- /dev/null +++ b/admin/i18n/nl/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Module toevoegen", + "Additional npm modules:": "Extra npm-modules", + "Allow creation of foreign objects": "Maken van vreemde objecten toestaan", + "Backups will not contain any projects or modules installed via the Palletmanager": "Back-ups bevatten geen projecten of modules die zijn geïnstalleerd via de Palletmanager!", + "Convert values to string:": "IoBroker-waarden converteren naar tekenreeks", + "Divided by comma": "Verdeeld door een komma", + "Enable Projects Feature:": "Projecten inschakelen", + "Leave blank to disable basic authentication": "Laat dit leeg om basisverificatie uit te schakelen", + "Max allocated RAM:": "Max toegewezen RAM", + "Module names": "Module namen", + "Password": "Wachtwoord", + "Safe mode": "Veilige modus", + "Update select dialog": "Update select dialoogvenster", + "Use palletmanager:": "Gebruik palletmanager", + "User": "Gebruiker", + "Web server port:": "Webserverpoort", + "http root directory:": "http root directory", + "node-red settings": "node-red instellingen", + "node-red update select dialog": "update select dialoogvenster" +} \ No newline at end of file diff --git a/admin/i18n/pl/translations.json b/admin/i18n/pl/translations.json new file mode 100644 index 0000000..e47caca --- /dev/null +++ b/admin/i18n/pl/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Dodaj moduł", + "Additional npm modules:": "Dodatkowe moduły npm", + "Allow creation of foreign objects": "Zezwól na tworzenie obcych obiektów", + "Backups will not contain any projects or modules installed via the Palletmanager": "Kopie zapasowe nie będą zawierać żadnych projektów ani modułów zainstalowanych za pośrednictwem Palletmanager!", + "Convert values to string:": "Konwertuj wartości ioBroker na ciąg", + "Divided by comma": "Podzielone przecinkiem", + "Enable Projects Feature:": "Włącz funkcję projektów", + "Leave blank to disable basic authentication": "Pozostaw puste, aby wyłączyć podstawowe uwierzytelnianie", + "Max allocated RAM:": "Maksymalna przydzielona pamięć RAM", + "Module names": "Nazwy modułów", + "Password": "Hasło", + "Safe mode": "Tryb bezpieczeństwa", + "Update select dialog": "Zaktualizuj wybrane okno dialogowe", + "Use palletmanager:": "Użyj menedżera palet", + "User": "Użytkownik", + "Web server port:": "Port serwera internetowego", + "http root directory:": "główny katalog http", + "node-red settings": "ustawienia node-red", + "node-red update select dialog": "okno dialogowe aktualizacji uaktualnienia węzła" +} \ No newline at end of file diff --git a/admin/i18n/pt/translations.json b/admin/i18n/pt/translations.json new file mode 100644 index 0000000..76e6e97 --- /dev/null +++ b/admin/i18n/pt/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Adicionar módulo", + "Additional npm modules:": "Módulos npm adicionais", + "Allow creation of foreign objects": "Permitir a criação de objetos estranhos", + "Backups will not contain any projects or modules installed via the Palletmanager": "Os backups não conterão nenhum projeto ou módulo instalado por meio do Palletmanager!", + "Convert values to string:": "Converter valores de ioBroker em string", + "Divided by comma": "Dividido por vírgula", + "Enable Projects Feature:": "Ativar recurso de projetos", + "Leave blank to disable basic authentication": "Deixe em branco para desativar a autenticação básica", + "Max allocated RAM:": "RAM alocada máxima", + "Module names": "Nomes de módulos", + "Password": "Senha", + "Safe mode": "Modo de segurança", + "Update select dialog": "Atualizar caixa de diálogo de seleção", + "Use palletmanager:": "Use palletmanager", + "User": "Do utilizador", + "Web server port:": "Porta do servidor da Web", + "http root directory:": "diretório raiz http", + "node-red settings": "configurações de nó vermelho", + "node-red update select dialog": "caixa de diálogo de seleção de atualização do nó-vermelho" +} \ No newline at end of file diff --git a/admin/i18n/ru/translations.json b/admin/i18n/ru/translations.json new file mode 100644 index 0000000..2e0924d --- /dev/null +++ b/admin/i18n/ru/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "Добавить модуль", + "Additional npm modules:": "Дополнительные NPM Модули", + "Allow creation of foreign objects": "Разрешить создание объектов не в этом адаптере", + "Backups will not contain any projects or modules installed via the Palletmanager": "Резервные копии не будут содержать никаких проектов или модулей, установленных через Palletmanager!", + "Convert values to string:": "Конвертировать значения из ioBroker в строки", + "Divided by comma": "Через запятую", + "Enable Projects Feature:": "Включить проекты", + "Leave blank to disable basic authentication": "Оставить пустым, чтобы отключить basic authentication", + "Max allocated RAM:": "Выделено RAM", + "Module names": "Имена модулей", + "Password": "Пароль", + "Safe mode": "Безопасный режим", + "Update select dialog": "Обновить переменные в диалоге выбора объектов", + "Use palletmanager:": "Используйте palletmanager", + "User": "Имя пользователя", + "Web server port:": "Порт веб сервера", + "http root directory:": "http root directory", + "node-red settings": "node-red Настройки", + "node-red update select dialog": "Обновить переменные в диалоге node-red" +} \ No newline at end of file diff --git a/admin/i18n/zh-cn/translations.json b/admin/i18n/zh-cn/translations.json new file mode 100644 index 0000000..7cdf055 --- /dev/null +++ b/admin/i18n/zh-cn/translations.json @@ -0,0 +1,21 @@ +{ + "Add module": "添加模块", + "Additional npm modules:": "额外的npm模块", + "Allow creation of foreign objects": "允许创建异物", + "Backups will not contain any projects or modules installed via the Palletmanager": "备份将不包含通过Palletmanager安装的任何项目或模块!", + "Convert values to string:": "将ioBroker值转换为字符串", + "Divided by comma": "逗号分隔", + "Enable Projects Feature:": "启用项目功能", + "Leave blank to disable basic authentication": "留空以禁用基本身份验证", + "Max allocated RAM:": "最大分配RAM", + "Module names": "模块名称", + "Password": "密码", + "Safe mode": "安全模式", + "Update select dialog": "更新选择对话框", + "Use palletmanager:": "使用托盘管理器", + "User": "用户", + "Web server port:": "Web服务器端口", + "http root directory:": "http根目录", + "node-red settings": "node-red设置", + "node-red update select dialog": "node-red update选择对话框" +} \ No newline at end of file diff --git a/admin/words.js b/admin/words.js index d74110c..b742fef 100644 --- a/admin/words.js +++ b/admin/words.js @@ -1,64 +1,24 @@ -// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n /*global systemDictionary:true */ 'use strict'; systemDictionary = { - "node-red settings": { "en": "node-red settings", "de": "node-red Einstellungen", "ru": "node-red Настройки", "pt": "configurações de nó vermelho", "nl": "node-red instellingen", "fr": "paramètres de node-red", "it": "impostazioni del node-red", "es": "configuración de node-red", "pl": "ustawienia node-red", "zh-cn": "node-red设置"}, - "Web server port:": { "en": "Web server port", "de": "Web-Server-Port", "ru": "Порт веб сервера", "pt": "Porta do servidor da Web", "nl": "Webserverpoort", "fr": "Port du serveur Web", "it": "Porta del server Web", "es": "Puerto del servidor web", "pl": "Port serwera internetowego", "zh-cn": "Web服务器端口"}, - "node-red update select dialog": { "en": "node-red update select dialog", "de": "node-red SelectID Dialog aktualisieren", "ru": "Обновить переменные в диалоге node-red", "pt": "caixa de diálogo de seleção de atualização do nó-vermelho", "nl": "update select dialoogvenster", "fr": "boîte de dialogue de sélection de mise à jour de noeud", "it": "finestra di dialogo di selezione aggiornamento node-red", "es": "diálogo de selección de actualización node-red", "pl": "okno dialogowe aktualizacji uaktualnienia węzła", "zh-cn": "node-red update选择对话框"}, - "Update select dialog": { "en": "Update select dialog", "de": "Update Dialog um ID zu selektieren", "ru": "Обновить переменные в диалоге выбора объектов", "pt": "Atualizar caixa de diálogo de seleção", "nl": "Update select dialoogvenster", "fr": "Mettre à jour le dialogue", "it": "Aggiorna la finestra di selezione", "es": "Actualizar diálogo de selección", "pl": "Zaktualizuj wybrane okno dialogowe", "zh-cn": "更新选择对话框"}, - "Divided by comma": { "en": "Divided by comma", "de": "Getrennt mit Komma", "ru": "Через запятую", "pt": "Dividido por vírgula", "nl": "Verdeeld door een komma", "fr": "Divisé par une virgule", "it": "Diviso in virgola", "es": "Dividido por coma", "pl": "Podzielone przecinkiem", "zh-cn": "逗号分隔"}, + "Add module": { "en": "Add module", "de": "Modul hinzufügen", "ru": "Добавить модуль", "pt": "Adicionar módulo", "nl": "Module toevoegen", "fr": "Ajouter un module", "it": "Aggiungi modulo", "es": "Agregar módulo", "pl": "Dodaj moduł", "zh-cn": "添加模块"}, "Additional npm modules:": { "en": "Additional npm modules", "de": "Zusätzliche NPM-Module", "ru": "Дополнительные NPM Модули", "pt": "Módulos npm adicionais", "nl": "Extra npm-modules", "fr": "Modules NPM supplémentaires", "it": "Ulteriori moduli npm", "es": "Módulos npm adicionales", "pl": "Dodatkowe moduły npm", "zh-cn": "额外的npm模块"}, - "http root directory:": { "en": "http root directory", "de": "http Stammpfad", "ru": "http root directory", "pt": "diretório raiz http", "nl": "http root directory", "fr": "répertoire racine http", "it": "directory root http", "es": "directorio raíz http", "pl": "główny katalog http", "zh-cn": "http根目录"}, + "Allow creation of foreign objects": { "en": "Allow creation of foreign objects", "de": "Erstellung von Fremd-Objekten zulassen", "ru": "Разрешить создание объектов не в этом адаптере", "pt": "Permitir a criação de objetos estranhos", "nl": "Maken van vreemde objecten toestaan", "fr": "Autoriser la création d'objets étrangers", "it": "Consentire la creazione di oggetti estranei", "es": "Permitir la creación de objetos extraños.", "pl": "Zezwól na tworzenie obcych obiektów", "zh-cn": "允许创建异物"}, + "Backups will not contain any projects or modules installed via the Palletmanager": {"en": "Backups will not contain any projects or modules installed via the Palletmanager!", "de": "Backups enthalten keine Projekte und auch keine Module die mit dem Palletenmanager installiert sind.", "ru": "Резервные копии не будут содержать никаких проектов или модулей, установленных через Palletmanager!", "pt": "Os backups não conterão nenhum projeto ou módulo instalado por meio do Palletmanager!", "nl": "Back-ups bevatten geen projecten of modules die zijn geïnstalleerd via de Palletmanager!", "fr": "Les sauvegardes ne contiendront aucun projet ou module installé via le Palletmanager!", "it": "I backup non conterranno progetti o moduli installati tramite Palletmanager!", "es": "¡Las copias de seguridad no contendrán ningún proyecto o módulo instalado a través del Palletmanager!", "pl": "Kopie zapasowe nie będą zawierać żadnych projektów ani modułów zainstalowanych za pośrednictwem Palletmanager!", "zh-cn": "备份将不包含通过Palletmanager安装的任何项目或模块!"}, "Convert values to string:": { "en": "Convert ioBroker values to string", "de": "ioBroker-Werte in String konvertieren:", "ru": "Конвертировать значения из ioBroker в строки", "pt": "Converter valores de ioBroker em string", "nl": "IoBroker-waarden converteren naar tekenreeks", "fr": "Convertir les valeurs de ioBroker en chaîne", "it": "Converti i valori di ioBroker in stringa", "es": "Convierta los valores de ioBroker en una cadena", "pl": "Konwertuj wartości ioBroker na ciąg", "zh-cn": "将ioBroker值转换为字符串"}, - "Add module": { "en": "Add module", "de": "Modul hinzufügen", "ru": "Добавить модуль", "pt": "Adicionar módulo", "nl": "Module toevoegen", "fr": "Ajouter un module", "it": "Aggiungi modulo", "es": "Agregar módulo", "pl": "Dodaj moduł", "zh-cn": "添加模块"}, + "Divided by comma": { "en": "Divided by comma", "de": "Getrennt mit Komma", "ru": "Через запятую", "pt": "Dividido por vírgula", "nl": "Verdeeld door een komma", "fr": "Divisé par une virgule", "it": "Diviso in virgola", "es": "Dividido por coma", "pl": "Podzielone przecinkiem", "zh-cn": "逗号分隔"}, + "Enable Projects Feature:": { "en": "Enable Projects Feature", "de": "Projektfunktion aktivieren", "ru": "Включить проекты", "pt": "Ativar recurso de projetos", "nl": "Projecten inschakelen", "fr": "Activer la fonctionnalité de projets", "it": "Abilita funzionalità progetti", "es": "Habilitar característica de proyectos", "pl": "Włącz funkcję projektów", "zh-cn": "启用项目功能"}, + "Leave blank to disable basic authentication": { "en": "Leave blank to disable basic authentication", "de": "Leer lassen, um die Basic-Authentication zu deaktivieren", "ru": "Оставить пустым, чтобы отключить basic authentication", "pt": "Deixe em branco para desativar a autenticação básica", "nl": "Laat dit leeg om basisverificatie uit te schakelen", "fr": "Laissez vide pour désactiver l'authentification de base", "it": "Lascia vuoto per disabilitare l'autenticazione di base", "es": "Dejar en blanco para deshabilitar la autenticación básica", "pl": "Pozostaw puste, aby wyłączyć podstawowe uwierzytelnianie", "zh-cn": "留空以禁用基本身份验证"}, "Max allocated RAM:": { "en": "Max allocated RAM", "de": "Max zugewiesener RAM", "ru": "Выделено RAM", "pt": "RAM alocada máxima", "nl": "Max toegewezen RAM", "fr": "Max allouée RAM", "it": "RAM allocata massima", "es": "RAM máxima asignada", "pl": "Maksymalna przydzielona pamięć RAM", "zh-cn": "最大分配RAM"}, "Module names": { "en": "Module names", "de": "Modulnamen", "ru": "Имена модулей", "pt": "Nomes de módulos", "nl": "Module namen", "fr": "Noms de modules", "it": "Nomi dei moduli", "es": "Nombres de módulos", "pl": "Nazwy modułów", "zh-cn": "模块名称"}, - "User": { "en": "User", "de": "Benutzer", "ru": "Имя пользователя", "pt": "Do utilizador", "nl": "Gebruiker", "fr": "Utilisateur", "it": "Utente", "es": "Usuario", "pl": "Użytkownik", "zh-cn": "用户"}, - "Leave blank to disable basic authentication": { "en": "Leave blank to disable basic authentication", "de": "Leer lassen, um die Basic-Authentication zu deaktivieren", "ru": "Оставить пустым, чтобы отключить basic authentication", "pt": "Deixe em branco para desativar a autenticação básica", "nl": "Laat dit leeg om basisverificatie uit te schakelen", "fr": "Laissez vide pour désactiver l'authentification de base", "it": "Lascia vuoto per disabilitare l'autenticazione di base", "es": "Dejar en blanco para deshabilitar la autenticación básica", "pl": "Pozostaw puste, aby wyłączyć podstawowe uwierzytelnianie", "zh-cn": "留空以禁用基本身份验证"}, "Password": { "en": "Password", "de": "Passwort", "ru": "Пароль", "pt": "Senha", "nl": "Wachtwoord", "fr": "Mot de passe", "it": "Parola d'ordine", "es": "Contraseña", "pl": "Hasło", "zh-cn": "密码"}, - "Enable Projects Feature:": { - "en": "Enable Projects Feature", - "de": "Projektfunktion aktivieren", - "ru": "Включить проекты", - "pt": "Ativar recurso de projetos", - "nl": "Projecten inschakelen", - "fr": "Activer la fonctionnalité de projets", - "it": "Abilita funzionalità progetti", - "es": "Habilitar característica de proyectos", - "pl": "Włącz funkcję projektów", - "zh-cn": "启用项目功能" - }, - "Allow creation of foreign objects": { - "en": "Allow creation of foreign objects", - "de": "Erstellung von Fremd-Objekten zulassen", - "ru": "Разрешить создание объектов не в этом адаптере", - "pt": "Permitir a criação de objetos estranhos", - "nl": "Maken van vreemde objecten toestaan", - "fr": "Autoriser la création d'objets étrangers", - "it": "Consentire la creazione di oggetti estranei", - "es": "Permitir la creación de objetos extraños.", - "pl": "Zezwól na tworzenie obcych obiektów", - "zh-cn": "允许创建异物" - }, - "Safe mode": { - "en": "Safe mode", - "de": "Sicherheitsmodus", - "ru": "Безопасный режим", - "pt": "Modo de segurança", - "nl": "Veilige modus", - "fr": "Mode sans échec", - "it": "Modalità sicura", - "es": "Modo seguro", - "pl": "Tryb bezpieczeństwa", - "zh-cn": "安全模式" - }, - "Use palletmanager:": { - "en": "Use palletmanager", - "de": "Palletenmanager benutzen" - }, - "Backups will not contain any projects or modules installed via the Palletmanager": { - "en": "Backups will not contain any projects or modules installed via the Palletmanager!", - "de": "Backups enthalten keine Projekte und auch keine Module die mit dem Palletenmanager installiert sind." - } + "Safe mode": { "en": "Safe mode", "de": "Sicherheitsmodus", "ru": "Безопасный режим", "pt": "Modo de segurança", "nl": "Veilige modus", "fr": "Mode sans échec", "it": "Modalità sicura", "es": "Modo seguro", "pl": "Tryb bezpieczeństwa", "zh-cn": "安全模式"}, + "Update select dialog": { "en": "Update select dialog", "de": "Update Dialog um ID zu selektieren", "ru": "Обновить переменные в диалоге выбора объектов", "pt": "Atualizar caixa de diálogo de seleção", "nl": "Update select dialoogvenster", "fr": "Mettre à jour le dialogue", "it": "Aggiorna la finestra di selezione", "es": "Actualizar diálogo de selección", "pl": "Zaktualizuj wybrane okno dialogowe", "zh-cn": "更新选择对话框"}, + "Use palletmanager:": { "en": "Use palletmanager", "de": "Palletenmanager benutzen", "ru": "Используйте palletmanager", "pt": "Use palletmanager", "nl": "Gebruik palletmanager", "fr": "Utiliser Palletmanager", "it": "Usa palletmanager", "es": "Utilice palletmanager", "pl": "Użyj menedżera palet", "zh-cn": "使用托盘管理器"}, + "User": { "en": "User", "de": "Benutzer", "ru": "Имя пользователя", "pt": "Do utilizador", "nl": "Gebruiker", "fr": "Utilisateur", "it": "Utente", "es": "Usuario", "pl": "Użytkownik", "zh-cn": "用户"}, + "Web server port:": { "en": "Web server port", "de": "Web-Server-Port", "ru": "Порт веб сервера", "pt": "Porta do servidor da Web", "nl": "Webserverpoort", "fr": "Port du serveur Web", "it": "Porta del server Web", "es": "Puerto del servidor web", "pl": "Port serwera internetowego", "zh-cn": "Web服务器端口"}, + "http root directory:": { "en": "http root directory", "de": "http Stammpfad", "ru": "http root directory", "pt": "diretório raiz http", "nl": "http root directory", "fr": "répertoire racine http", "it": "directory root http", "es": "directorio raíz http", "pl": "główny katalog http", "zh-cn": "http根目录"}, + "node-red settings": { "en": "node-red settings", "de": "node-red Einstellungen", "ru": "node-red Настройки", "pt": "configurações de nó vermelho", "nl": "node-red instellingen", "fr": "paramètres de node-red", "it": "impostazioni del node-red", "es": "configuración de node-red", "pl": "ustawienia node-red", "zh-cn": "node-red设置"}, + "node-red update select dialog": { "en": "node-red update select dialog", "de": "node-red SelectID Dialog aktualisieren", "ru": "Обновить переменные в диалоге node-red", "pt": "caixa de diálogo de seleção de atualização do nó-vermelho", "nl": "update select dialoogvenster", "fr": "boîte de dialogue de sélection de mise à jour de noeud", "it": "finestra di dialogo di selezione aggiornamento node-red", "es": "diálogo de selección de actualización node-red", "pl": "okno dialogowe aktualizacji uaktualnienia węzła", "zh-cn": "node-red update选择对话框"}, }; \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index e2207ef..a5d5acf 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,19 +1,18 @@ +/*! + * ioBroker gulpfile + * Date: 2019-01-28 + */ 'use strict'; -const gulp = require('gulp'); -const fs = require('fs'); -const pkg = require('./package.json'); +const gulp = require('gulp'); +const fs = require('fs'); +const pkg = require('./package.json'); const iopackage = require('./io-package.json'); -const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version; -/*const appName = getAppName(); - -function getAppName() { - const parts = __dirname.replace(/\\/g, '/').split('/'); - return parts[parts.length - 1].split('.')[0].toLowerCase(); -} -*/ +const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version; const fileName = 'words.js'; -const languages = { +const EMPTY = ''; +const translate = require('./lib/tools').translateText; +const languages = { en: {}, de: {}, ru: {}, @@ -26,23 +25,18 @@ const languages = { 'zh-cn': {} }; -function lang2data(lang, isFlat) { - let str = isFlat ? '' : '{\n'; +function lang2data(lang) { + let str ='{\n'; let count = 0; for (const w in lang) { if (lang.hasOwnProperty(w)) { count++; - if (isFlat) { - str += (lang[w] === '' ? (isFlat[w] || w) : lang[w]) + '\n'; - } else { - const key = ' "' + w.replace(/"/g, '\\"') + '": '; - str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n'; - } + const key = ' "' + w.replace(/"/g, '\\"') + '": '; + str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n'; } } - if (!count) return isFlat ? '' : '{\n}'; - if (isFlat) { - return str; + if (!count) { + return '{\n}'; } else { return str.substring(0, str.length - 2) + '\n}'; } @@ -56,26 +50,9 @@ function readWordJs(src) { } else { words = fs.readFileSync(src + fileName).toString(); } + words = words.substring(words.indexOf('{'), words.length); + words = words.substring(0, words.lastIndexOf(';')); - const lines = words.split(/\r\n|\r|\n/g); - let i = 0; - while (!lines[i].match(/^systemDictionary = {/)) { - i++; - } - lines.splice(0, i); - - // remove last empty lines - i = lines.length - 1; - while (!lines[i]) { - i--; - } - if (i < lines.length - 1) { - lines.splice(i + 1); - } - - lines[0] = lines[0].replace('systemDictionary = ', ''); - lines[lines.length - 1] = lines[lines.length - 1].trim().replace(/};$/, '}'); - words = lines.join('\n'); const resultFunc = new Function('return ' + words + ';'); return resultFunc(); @@ -83,14 +60,15 @@ function readWordJs(src) { return null; } } + function padRight(text, totalLength) { return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : ''); } + function writeWordJs(data, src) { - let text = '// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n\n'; + let text = ''; text += '/*global systemDictionary:true */\n'; - text += '\'use strict\';\n\n'; - + text += "'use strict';\n\n"; text += 'systemDictionary = {\n'; for (const word in data) { if (data.hasOwnProperty(word)) { @@ -109,7 +87,6 @@ function writeWordJs(data, src) { } } text += '};'; - if (fs.existsSync(src + 'js/' + fileName)) { fs.writeFileSync(src + 'js/' + fileName, text); } else { @@ -117,8 +94,6 @@ function writeWordJs(data, src) { } } -const EMPTY = ''; - function words2languages(src) { const langs = Object.assign({}, languages); const data = readWordJs(src); @@ -142,9 +117,10 @@ function words2languages(src) { fs.mkdirSync(src + 'i18n/'); } for (const l in langs) { - if (!langs.hasOwnProperty(l)) continue; + if (!langs.hasOwnProperty(l)) + continue; const keys = Object.keys(langs[l]); - //keys.sort(); + keys.sort(); const obj = {}; for (let k = 0; k < keys.length; k++) { obj[keys[k]] = langs[l][keys[k]]; @@ -159,52 +135,8 @@ function words2languages(src) { console.error('Cannot read or parse ' + fileName); } } -function words2languagesFlat(src) { - const langs = Object.assign({}, languages); - const data = readWordJs(src); - if (data) { - for (const word in data) { - if (data.hasOwnProperty(word)) { - for (const lang in data[word]) { - if (data[word].hasOwnProperty(lang)) { - langs[lang][word] = data[word][lang]; - // pre-fill all other languages - for (const j in langs) { - if (langs.hasOwnProperty(j)) { - langs[j][word] = langs[j][word] || EMPTY; - } - } - } - } - } - } - const keys = Object.keys(langs.en); - //keys.sort(); - for (const l in langs) { - if (!langs.hasOwnProperty(l)) continue; - const obj = {}; - for (let k = 0; k < keys.length; k++) { - obj[keys[k]] = langs[l][keys[k]]; - } - langs[l] = obj; - } - if (!fs.existsSync(src + 'i18n/')) { - fs.mkdirSync(src + 'i18n/'); - } - for (const ll in langs) { - if (!langs.hasOwnProperty(ll)) continue; - if (!fs.existsSync(src + 'i18n/' + ll)) { - fs.mkdirSync(src + 'i18n/' + ll); - } - fs.writeFileSync(src + 'i18n/' + ll + '/flat.txt', lang2data(langs[ll], langs.en)); - } - fs.writeFileSync(src + 'i18n/flat.txt', keys.join('\n')); - } else { - console.error('Cannot read or parse ' + fileName); - } -} -function languagesFlat2words(src) { +function languages2words(src) { const dirs = fs.readdirSync(src + 'i18n/'); const langs = {}; const bigOne = {}; @@ -213,30 +145,28 @@ function languagesFlat2words(src) { const posA = order.indexOf(a); const posB = order.indexOf(b); if (posA === -1 && posB === -1) { - if (a > b) return 1; - if (a < b) return -1; + if (a > b) + return 1; + if (a < b) + return -1; return 0; } else if (posA === -1) { return -1; } else if (posB === -1) { return 1; } else { - if (posA > posB) return 1; - if (posA < posB) return -1; + if (posA > posB) + return 1; + if (posA < posB) + return -1; return 0; } }); - const keys = fs.readFileSync(src + 'i18n/flat.txt').toString().split('\n'); - - for (let l = 0; l < dirs.length; l++) { - if (dirs[l] === 'flat.txt') continue; - const lang = dirs[l]; - const values = fs.readFileSync(src + 'i18n/' + lang + '/flat.txt').toString().split('\n'); - langs[lang] = {}; - keys.forEach(function (word, i) { - langs[lang][word] = values[i].replace(/<\/ i>/g, '').replace(/<\/ b>/g, '').replace(/<\/ span>/g, '').replace(/% s/g, ' %s'); - }); - + for (const lang of dirs) { + if (lang === 'flat.txt') + continue; + langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString(); + langs[lang] = JSON.parse(langs[lang]); const words = langs[lang]; for (const word in words) { if (words.hasOwnProperty(word)) { @@ -250,17 +180,18 @@ function languagesFlat2words(src) { // read actual words.js const aWords = readWordJs(); - const temporaryIgnore = ['pt', 'fr', 'nl', 'flat.txt']; + const temporaryIgnore = ['flat.txt']; if (aWords) { // Merge words together for (const w in aWords) { if (aWords.hasOwnProperty(w)) { if (!bigOne[w]) { console.warn('Take from actual words.js: ' + w); - bigOne[w] = aWords[w] + bigOne[w] = aWords[w]; } dirs.forEach(function (lang) { - if (temporaryIgnore.indexOf(lang) !== -1) return; + if (temporaryIgnore.indexOf(lang) !== -1) + return; if (!bigOne[w][lang]) { console.warn('Missing "' + lang + '": ' + w); } @@ -272,85 +203,32 @@ function languagesFlat2words(src) { writeWordJs(bigOne, src); } -function languages2words(src) { - const dirs = fs.readdirSync(src + 'i18n/'); - const langs = {}; - const bigOne = {}; - const order = Object.keys(languages); - dirs.sort(function (a, b) { - const posA = order.indexOf(a); - const posB = order.indexOf(b); - if (posA === -1 && posB === -1) { - if (a > b) return 1; - if (a < b) return -1; - return 0; - } else if (posA === -1) { - return -1; - } else if (posB === -1) { - return 1; - } else { - if (posA > posB) return 1; - if (posA < posB) return -1; - return 0; - } - }); - for (let l = 0; l < dirs.length; l++) { - if (dirs[l] === 'flat.txt') continue; - const lang = dirs[l]; - langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString(); - langs[lang] = JSON.parse(langs[lang]); - const words = langs[lang]; - for (const word in words) { - if (words.hasOwnProperty(word)) { - bigOne[word] = bigOne[word] || {}; - if (words[word] !== EMPTY) { - bigOne[word][lang] = words[word]; - } - } - } + +async function translateNotExisting(obj, baseText, yandex) { + let t = obj['en']; + if (!t) { + t = baseText; } - // read actual words.js - const aWords = readWordJs(); - const temporaryIgnore = ['pt', 'fr', 'nl', 'it']; - if (aWords) { - // Merge words together - for (const w in aWords) { - if (aWords.hasOwnProperty(w)) { - if (!bigOne[w]) { - console.warn('Take from actual words.js: ' + w); - bigOne[w] = aWords[w] - } - dirs.forEach(function (lang) { - if (temporaryIgnore.indexOf(lang) !== -1) return; - if (!bigOne[w][lang]) { - console.warn('Missing "' + lang + '": ' + w); - } - }); + if (t) { + for (let l in languages) { + if (!obj[l]) { + const time = new Date().getTime(); + obj[l] = await translate(t, l, yandex); + console.log('en -> ' + l + ' ' + (new Date().getTime() - time) + ' ms'); } } - } - - writeWordJs(bigOne, src); } -gulp.task('words.js => json', function (done) { - words2languages('./admin/'); - done(); -}); - -gulp.task('words.js => flat', function (done) { - words2languagesFlat('./admin/'); - done(); -}); +//TASKS -gulp.task('flat => words.js', function (done) { - languagesFlat2words('./admin/'); +gulp.task('adminWords2languages', function (done) { + words2languages('./admin/'); done(); }); -gulp.task('json => words.js', function (done) { +gulp.task('adminLanguages2words', function (done) { languages2words('./admin/'); done(); }); @@ -366,7 +244,13 @@ gulp.task('updatePackages', function (done) { en: 'news', de: 'neues', ru: 'новое', - 'zh-cn': '消息' + pt: 'novidades', + nl: 'nieuws', + fr: 'nouvelles', + it: 'notizie', + es: 'noticias', + pl: 'nowości', + 'zh-cn': '新' }; iopackage.common.news = Object.assign(newNews, news); } @@ -379,7 +263,7 @@ gulp.task('updateReadme', function (done) { const pos = readme.indexOf('## Changelog\n'); if (pos !== -1) { const readmeStart = readme.substring(0, pos + '## Changelog\n'.length); - const readmeEnd = readme.substring(pos + '## Changelog\n'.length); + const readmeEnd = readme.substring(pos + '## Changelog\n'.length); if (readme.indexOf(version) === -1) { const timestamp = new Date(); @@ -398,4 +282,56 @@ gulp.task('updateReadme', function (done) { done(); }); -gulp.task('default', gulp.series('updatePackages', 'updateReadme')); +gulp.task('translate', async function (done) { + + let yandex; + const i = process.argv.indexOf('--yandex'); + if (i > -1) { + yandex = process.argv[i + 1]; + } + + if (iopackage && iopackage.common) { + if (iopackage.common.news) { + console.log('Translate News'); + for (let k in iopackage.common.news) { + console.log('News: ' + k); + let nw = iopackage.common.news[k]; + await translateNotExisting(nw, null, yandex); + } + } + if (iopackage.common.titleLang) { + console.log('Translate Title'); + await translateNotExisting(iopackage.common.titleLang, iopackage.common.title, yandex); + } + if (iopackage.common.desc) { + console.log('Translate Description'); + await translateNotExisting(iopackage.common.desc, null, yandex); + } + + if (fs.existsSync('./admin/i18n/en/translations.json')) { + let enTranslations = require('./admin/i18n/en/translations.json'); + for (let l in languages) { + console.log('Translate Text: ' + l); + let existing = {}; + if (fs.existsSync('./admin/i18n/' + l + '/translations.json')) { + existing = require('./admin/i18n/' + l + '/translations.json'); + } + for (let t in enTranslations) { + if (!existing[t]) { + existing[t] = await translate(enTranslations[t], l, yandex); + } + } + if (!fs.existsSync('./admin/i18n/' + l + '/')) { + fs.mkdirSync('./admin/i18n/' + l + '/'); + } + fs.writeFileSync('./admin/i18n/' + l + '/translations.json', JSON.stringify(existing, null, 4)); + } + } + + } + fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4)); +}); + +gulp.task('translateAndUpdateWordsJS', gulp.series('translate', 'adminLanguages2words', 'adminWords2languages')); + +gulp.task('default', gulp.series('updatePackages', 'updateReadme')); \ No newline at end of file diff --git a/lib/tools.js b/lib/tools.js new file mode 100644 index 0000000..ec0ad32 --- /dev/null +++ b/lib/tools.js @@ -0,0 +1,99 @@ +const axios = require('axios').default; + +/** + * Tests whether the given variable is a real object and not an Array + * @param {any} it The variable to test + * @returns {it is Record} + */ +function isObject(it) { + // This is necessary because: + // typeof null === 'object' + // typeof [] === 'object' + // [] instanceof Object === true + return Object.prototype.toString.call(it) === '[object Object]'; +} + +/** + * Tests whether the given variable is really an Array + * @param {any} it The variable to test + * @returns {it is any[]} + */ +function isArray(it) { + if (typeof Array.isArray === 'function') return Array.isArray(it); + return Object.prototype.toString.call(it) === '[object Array]'; +} + +/** + * Translates text to the target language. Automatically chooses the right translation API. + * @param {string} text The text to translate + * @param {string} targetLang The target languate + * @param {string} [yandexApiKey] The yandex API key. You can create one for free at https://translate.yandex.com/developers + * @returns {Promise} + */ +async function translateText(text, targetLang, yandexApiKey) { + if (targetLang === 'en') { + return text; + } else if (!text) { + return ''; + } + if (yandexApiKey) { + return translateYandex(text, targetLang, yandexApiKey); + } else { + return translateGoogle(text, targetLang); + } +} + +/** + * Translates text with Yandex API + * @param {string} text The text to translate + * @param {string} targetLang The target languate + * @param {string} apiKey The yandex API key. You can create one for free at https://translate.yandex.com/developers + * @returns {Promise} + */ +async function translateYandex(text, targetLang, apiKey) { + if (targetLang === 'zh-cn') { + targetLang = 'zh'; + } + try { + const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apiKey}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`; + const response = await axios({url, timeout: 15000}); + if (response.data && response.data.text && isArray(response.data.text)) { + return response.data.text[0]; + } + throw new Error('Invalid response for translate request'); + } catch (e) { + throw new Error(`Could not translate to "${targetLang}": ${e}`); + } +} + +/** + * Translates text with Google API + * @param {string} text The text to translate + * @param {string} targetLang The target languate + * @returns {Promise} + */ +async function translateGoogle(text, targetLang) { + try { + const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`; + const response = await axios({url, timeout: 15000}); + if (isArray(response.data)) { + // we got a valid response + return response.data[0][0][0]; + } + throw new Error('Invalid response for translate request'); + } catch (e) { + if (e.response && e.response.status === 429) { + throw new Error( + `Could not translate to "${targetLang}": Rate-limited by Google Translate` + ); + } else { + throw new Error(`Could not translate to "${targetLang}": ${e}`); + } + } +} + +module.exports = { + isArray, + isObject, + translateText +}; diff --git a/package.json b/package.json index 836333d..700605c 100644 --- a/package.json +++ b/package.json @@ -27,26 +27,27 @@ "js2xmlparser": "^4.0.1", "fs.notify": "^0.0.4", "feedparser": "^2.2.10", - "mongodb": "^3.6.4", + "mongodb": "^3.6.6", "node-red-contrib-os": "^0.2.0" }, "dependencies": { - "node-red": "^1.2.9", - "node-red-dashboard": "^2.28.1", - "node-red-contrib-aggregator": "^1.5.0", + "node-red": "^1.3.2", + "node-red-dashboard": "^2.28.2", + "node-red-contrib-aggregator": "^2.0.0", "node-red-contrib-polymer": "^0.0.22", - "node-red-node-email": "^1.8.3", - "node-red-node-feedparser": "^0.1.16", + "node-red-node-email": "^1.12.0", + "node-red-node-feedparser": "^0.2.1", "node-red-node-sentiment": "^0.1.6", - "node-red-node-twitter": "^1.1.7", + "node-red-node-twitter": "^1.2.0", "@iobroker/adapter-core": "^2.4.0" }, "devDependencies": { "@alcalzone/release-script": "^1.8.3", + "axios": "^0.21.1", "gulp": "^4.0.2", "request": "^2.88.2", - "mocha": "^8.3.1", - "chai": "^4.3.3" + "mocha": "^8.3.2", + "chai": "^4.3.4" }, "bugs": { "url": "https://github.com/ioBroker/ioBroker.node-red/issues" diff --git a/settings.js b/settings.js index 333c4d3..04a9a62 100644 --- a/settings.js +++ b/settings.js @@ -1,311 +1,313 @@ -/** - * This is the default settings file provided by Node-RED. - * - * It can contain any valid JavaScript code that will get run when Node-RED - * is started. - * - * Lines that start with // are commented out. - * Each entry should be separated from the entries above and below by a comma ',' - * - * For more information about individual settings, refer to the documentation: - * https://nodered.org/docs/user-guide/runtime/configuration - **/ - -module.exports = { - // the tcp port that the Node-RED web server is listening on - uiPort: '%%port%%', - - // By default, the Node-RED UI accepts connections on all IPv4 interfaces. - // To listen on all IPv6 addresses, set uiHost to "::", - // The following property can be used to listen on a specific interface. For - // example, the following would only allow connections from the local machine. - //uiHost: "127.0.0.1", - uiHost: '%%bind%%', - - iobrokerInstance: '%%instance%%', - iobrokerConfig: '%%config%%', - allowCreationOfForeignObjects: '%%allowCreationOfForeignObjects%%', - - // Retry time in milliseconds for MQTT connections - mqttReconnectTime: 15000, - - // Retry time in milliseconds for Serial port connections - serialReconnectTime: 15000, - - // Retry time in milliseconds for TCP socket connections - //socketReconnectTime: 10000, - - // Timeout in milliseconds for TCP server socket connections - // defaults to no timeout - //socketTimeout: 120000, - - // Maximum number of messages to wait in queue while attempting to connect to TCP socket - // defaults to 1000 - //tcpMsgQueueSize: 2000, - - // Timeout in milliseconds for HTTP request connections - // defaults to 120 seconds - //httpRequestTimeout: 120000, - - // The maximum length, in characters, of any message sent to the debug sidebar tab - debugMaxLength: 1000, - - // The maximum number of messages nodes will buffer internally as part of their - // operation. This applies across a range of nodes that operate on message sequences. - // defaults to no limit. A value of 0 also means no limit is applied. - //nodeMessageBufferMaxLength: 0, - - // To disable the option for using local files for storing keys and certificates in the TLS configuration - // node, set this to true - //tlsConfigDisableLocalFiles: true, - - // Colourise the console output of the debug node - //debugUseColors: true, - - // The file containing the flows. If not set, it defaults to flows_.json - flowFile: 'flows.json', - - // To enabled pretty-printing of the flow within the flow file, set the following - // property to true: - flowFilePretty: true, - - // By default, credentials are encrypted in storage using a generated key. To - // specify your own secret, set the following property. - // If you want to disable encryption of credentials, set this property to false. - // Note: once you set this property, do not change it - doing so will prevent - // node-red from being able to decrypt your existing credentials and they will be - // lost. - credentialSecret: "'%%credentialSecret%%'", - - // By default, all user data is stored in a directory called `.node-red` under - // the user's home directory. To use a different location, the following - // property can be used - userDir: __dirname + '/', - - // Node-RED scans the `nodes` directory in the userDir to find local node files. - // The following property can be used to specify an additional directory to scan. - nodesDir: '%%nodesdir%%', - - // By default, the Node-RED UI is available at http://localhost:1880/ - // The following property can be used to specify a different root path. - // If set to false, this is disabled. - //httpAdminRoot: '/admin', - - // Some nodes, such as HTTP In, can be used to listen for incoming http requests. - // By default, these are served relative to '/'. The following property - // can be used to specifiy a different root path. If set to false, this is - // disabled. - //httpNodeRoot: '/red-nodes', - - // The following property can be used in place of 'httpAdminRoot' and 'httpNodeRoot', - // to apply the same root to both parts. - httpRoot: "'%%httpRoot%%'", - - // When httpAdminRoot is used to move the UI to a different root path, the - // following property can be used to identify a directory of static content - // that should be served at http://localhost:1880/. - //httpStatic: '/home/nol/node-red-static/', - - // The maximum size of HTTP request that will be accepted by the runtime api. - // Default: 5mb - //apiMaxLength: '5mb', - - // If you installed the optional node-red-dashboard you can set it's path - // relative to httpRoot - //ui: { path: "ui" }, - - // Securing Node-RED - // ----------------- - // To password protect the Node-RED editor and admin API, the following - // property can be used. See http://nodered.org/docs/security.html for details. - //adminAuth: { - // type: "credentials", - // users: [{ - // username: "admin", - // password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.", - // permissions: "*" - // }] - //}, - //httpAdminAuth: '%%auth%%', //Replaced by adminAuth in #99 - adminAuth: '%%auth%%', - - // To password protect the node-defined HTTP endpoints (httpNodeRoot), or - // the static content (httpStatic), the following properties can be used. - // The pass field is a bcrypt hash of the password. - // See http://nodered.org/docs/security.html#generating-the-password-hash - //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, - //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, - - // The following property can be used to enable HTTPS - // See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener - // for details on its contents. - // This property can be either an object, containing both a (private) key and a (public) certificate, - // or a function that returns such an object: - //// https object: - //https: { - // key: require("fs").readFileSync('privkey.pem'), - // cert: require("fs").readFileSync('cert.pem') - //}, - ////https function: - // https: function() { - // // This function should return the options object, or a Promise - // // that resolves to the options object - // return { - // key: require("fs").readFileSync('privkey.pem'), - // cert: require("fs").readFileSync('cert.pem') - // } - // }, - '%%secure%%'https: { key: require("fs").readFileSync("'%%certPrivate%%'"), cert: require("fs").readFileSync("'%%certPublic%%'") }, - - // The following property can be used to refresh the https settings at a - // regular time interval in hours. - // This requires: - // - the `https` setting to be a function that can be called to get - // the refreshed settings. - // - Node.js 11 or later. - //httpsRefreshInterval : 12, - - // The following property can be used to cause insecure HTTP connections to - // be redirected to HTTPS. - //requireHttps: true, - - // The following property can be used to disable the editor. The admin API - // is not affected by this option. To disable both the editor and the admin - // API, use either the httpRoot or httpAdminRoot properties - //disableEditor: false, - - // The following property can be used to configure cross-origin resource sharing - // in the HTTP nodes. - // See https://github.com/troygoode/node-cors#configuration-options for - // details on its contents. The following is a basic permissive set of options: - //httpNodeCors: { - // origin: "*", - // methods: "GET,PUT,POST,DELETE" - //}, - - // If you need to set an http proxy please set an environment variable - // called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system. - // For example - http_proxy=http://myproxy.com:8080 - // (Setting it here will have no effect) - // You may also specify no_proxy (or NO_PROXY) to supply a comma separated - // list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk - - // The following property can be used to add a custom middleware function - // in front of all http in nodes. This allows custom authentication to be - // applied to all http in nodes, or any other sort of common request processing. - //httpNodeMiddleware: function(req,res,next) { - // // Handle/reject the request, or pass it on to the http in node by calling next(); - // // Optionally skip our rawBodyParser by setting this to true; - // //req.skipRawBodyParser = true; - // next(); - //}, - - - // The following property can be used to add a custom middleware function - // in front of all admin http routes. For example, to set custom http - // headers - // httpAdminMiddleware: function(req,res,next) { - // // Set the X-Frame-Options header to limit where the editor - // // can be embedded - // //res.set('X-Frame-Options', 'sameorigin'); - // next(); - // }, - - // The following property can be used to pass custom options to the Express.js - // server used by Node-RED. For a full list of available options, refer - // to http://expressjs.com/en/api.html#app.settings.table - //httpServerOptions: { }, - - // The following property can be used to verify websocket connection attempts. - // This allows, for example, the HTTP request headers to be checked to ensure - // they include valid authentication information. - //webSocketNodeVerifyClient: function(info) { - // // 'info' has three properties: - // // - origin : the value in the Origin header - // // - req : the HTTP request - // // - secure : true if req.connection.authorized or req.connection.encrypted is set - // // - // // The function should return true if the connection should be accepted, false otherwise. - // // - // // Alternatively, if this function is defined to accept a second argument, callback, - // // it can be used to verify the client asynchronously. - // // The callback takes three arguments: - // // - result : boolean, whether to accept the connection or not - // // - code : if result is false, the HTTP error status to return - // // - reason: if result is false, the HTTP reason string to return - //}, - - // The following property can be used to seed Global Context with predefined - // values. This allows extra node modules to be made available with the - // Function node. - // For example, - // functionGlobalContext: { os:require('os') } - // can be accessed in a function block as: - // global.get("os") - - valueConvert: '%%valueConvert%%', - - functionGlobalContext: { - //'%%functionGlobalContext%%' - // os:require('os'), - // jfive:require("johnny-five"), - // j5board:require("johnny-five").Board({repl:false}) - }, - // `global.keys()` returns a list of all properties set in global context. - // This allows them to be displayed in the Context Sidebar within the editor. - // In some circumstances it is not desirable to expose them to the editor. The - // following property can be used to hide any property set in `functionGlobalContext` - // from being list by `global.keys()`. - // By default, the property is set to false to avoid accidental exposure of - // their values. Setting this to true will cause the keys to be listed. - exportGlobalContextKeys: false, - - - // Context Storage - // The following property can be used to enable context storage. The configuration - // provided here will enable file-based context that flushes to disk every 30 seconds. - // Refer to the documentation for further options: https://nodered.org/docs/api/context/ - // - //contextStorage: { - // default: { - // module:"localfilesystem" - // }, - //}, - - // The following property can be used to order the categories in the editor - // palette. If a node's category is not in the list, the category will get - // added to the end of the palette. - // If not set, the following default order is used: - //paletteCategories: ['subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'], - - // Configure the logging output - logging: { - // Only console logging is currently supported - console: { - // Level of logging to be recorded. Options are: - // fatal - only those errors which make the application unusable should be recorded - // error - record errors which are deemed fatal for a particular request + fatal errors - // warn - record problems which are non fatal + errors + fatal errors - // info - record information about the general running of the application + warn + error + fatal errors - // debug - record information which is more verbose than info + info + warn + error + fatal errors - // trace - record very detailed logging + debug + info + warn + error + fatal errors - // off - turn off all logging (doesn't affect metrics or audit) - level: "info", - // Whether or not to include metric events in the log output - metrics: false, - // Whether or not to include audit events in the log output - audit: false - } - }, - - // Customising the editor - editorTheme: { - projects: { - // To enable the Projects feature, set this value to true - enabled: '%%projectsEnabled%%' - }, - palette: { - editable: '%%palletmanagerEnabled%%' - } - } -}; +/** + * This is the default settings file provided by Node-RED. + * + * It can contain any valid JavaScript code that will get run when Node-RED + * is started. + * + * Lines that start with // are commented out. + * Each entry should be separated from the entries above and below by a comma ',' + * + * For more information about individual settings, refer to the documentation: + * https://nodered.org/docs/user-guide/runtime/configuration + **/ + +module.exports = { + // the tcp port that the Node-RED web server is listening on + uiPort: '%%port%%', + + // By default, the Node-RED UI accepts connections on all IPv4 interfaces. + // To listen on all IPv6 addresses, set uiHost to "::", + // The following property can be used to listen on a specific interface. For + // example, the following would only allow connections from the local machine. + //uiHost: "127.0.0.1", + uiHost: '%%bind%%', + + iobrokerInstance: '%%instance%%', + iobrokerConfig: '%%config%%', + allowCreationOfForeignObjects: '%%allowCreationOfForeignObjects%%', + + // Retry time in milliseconds for MQTT connections + mqttReconnectTime: 15000, + + // Retry time in milliseconds for Serial port connections + serialReconnectTime: 15000, + + // Retry time in milliseconds for TCP socket connections + //socketReconnectTime: 10000, + + // Timeout in milliseconds for TCP server socket connections + // defaults to no timeout + //socketTimeout: 120000, + + // Maximum number of messages to wait in queue while attempting to connect to TCP socket + // defaults to 1000 + //tcpMsgQueueSize: 2000, + + // Timeout in milliseconds for HTTP request connections + // defaults to 120 seconds + //httpRequestTimeout: 120000, + + // The maximum length, in characters, of any message sent to the debug sidebar tab + debugMaxLength: 1000, + + // The maximum number of messages nodes will buffer internally as part of their + // operation. This applies across a range of nodes that operate on message sequences. + // defaults to no limit. A value of 0 also means no limit is applied. + //nodeMessageBufferMaxLength: 0, + + // To disable the option for using local files for storing keys and certificates in the TLS configuration + // node, set this to true + //tlsConfigDisableLocalFiles: true, + + // Colourise the console output of the debug node + //debugUseColors: true, + + // The file containing the flows. If not set, it defaults to flows_.json + flowFile: 'flows.json', + + // To enabled pretty-printing of the flow within the flow file, set the following + // property to true: + flowFilePretty: true, + + // By default, credentials are encrypted in storage using a generated key. To + // specify your own secret, set the following property. + // If you want to disable encryption of credentials, set this property to false. + // Note: once you set this property, do not change it - doing so will prevent + // node-red from being able to decrypt your existing credentials and they will be + // lost. + credentialSecret: "'%%credentialSecret%%'", + + // By default, all user data is stored in a directory called `.node-red` under + // the user's home directory. To use a different location, the following + // property can be used + userDir: __dirname + '/', + + // Node-RED scans the `nodes` directory in the userDir to find local node files. + // The following property can be used to specify an additional directory to scan. + nodesDir: '%%nodesdir%%', + + // By default, the Node-RED UI is available at http://localhost:1880/ + // The following property can be used to specify a different root path. + // If set to false, this is disabled. + //httpAdminRoot: '/admin', + + // Some nodes, such as HTTP In, can be used to listen for incoming http requests. + // By default, these are served relative to '/'. The following property + // can be used to specifiy a different root path. If set to false, this is + // disabled. + //httpNodeRoot: '/red-nodes', + + // The following property can be used in place of 'httpAdminRoot' and 'httpNodeRoot', + // to apply the same root to both parts. + httpRoot: "'%%httpRoot%%'", + + // When httpAdminRoot is used to move the UI to a different root path, the + // following property can be used to identify a directory of static content + // that should be served at http://localhost:1880/. + //httpStatic: '/home/nol/node-red-static/', + + // The maximum size of HTTP request that will be accepted by the runtime api. + // Default: 5mb + //apiMaxLength: '5mb', + + // If you installed the optional node-red-dashboard you can set it's path + // relative to httpRoot + //ui: { path: "ui" }, + + // Securing Node-RED + // ----------------- + // To password protect the Node-RED editor and admin API, the following + // property can be used. See http://nodered.org/docs/security.html for details. + //adminAuth: { + // type: "credentials", + // users: [{ + // username: "admin", + // password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.", + // permissions: "*" + // }] + //}, + //httpAdminAuth: '%%auth%%', //Replaced by adminAuth in #99 + adminAuth: '%%auth%%', + + // To password protect the node-defined HTTP endpoints (httpNodeRoot), or + // the static content (httpStatic), the following properties can be used. + // The pass field is a bcrypt hash of the password. + // See http://nodered.org/docs/security.html#generating-the-password-hash + //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + + // The following property can be used to enable HTTPS + // See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener + // for details on its contents. + // This property can be either an object, containing both a (private) key and a (public) certificate, + // or a function that returns such an object: + //// https object: + //https: { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + //}, + ////https function: + // https: function() { + // // This function should return the options object, or a Promise + // // that resolves to the options object + // return { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + // } + // }, + '%%secure%%'https: { key: require("fs").readFileSync("'%%certPrivate%%'"), cert: require("fs").readFileSync("'%%certPublic%%'") }, + + // The following property can be used to refresh the https settings at a + // regular time interval in hours. + // This requires: + // - the `https` setting to be a function that can be called to get + // the refreshed settings. + // - Node.js 11 or later. + //httpsRefreshInterval : 12, + + // The following property can be used to cause insecure HTTP connections to + // be redirected to HTTPS. + //requireHttps: true, + + // The following property can be used to disable the editor. The admin API + // is not affected by this option. To disable both the editor and the admin + // API, use either the httpRoot or httpAdminRoot properties + //disableEditor: false, + + // The following property can be used to configure cross-origin resource sharing + // in the HTTP nodes. + // See https://github.com/troygoode/node-cors#configuration-options for + // details on its contents. The following is a basic permissive set of options: + //httpNodeCors: { + // origin: "*", + // methods: "GET,PUT,POST,DELETE" + //}, + + // If you need to set an http proxy please set an environment variable + // called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system. + // For example - http_proxy=http://myproxy.com:8080 + // (Setting it here will have no effect) + // You may also specify no_proxy (or NO_PROXY) to supply a comma separated + // list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk + + // The following property can be used to add a custom middleware function + // in front of all http in nodes. This allows custom authentication to be + // applied to all http in nodes, or any other sort of common request processing. + //httpNodeMiddleware: function(req,res,next) { + // // Handle/reject the request, or pass it on to the http in node by calling next(); + // // Optionally skip our rawBodyParser by setting this to true; + // //req.skipRawBodyParser = true; + // next(); + //}, + + + // The following property can be used to add a custom middleware function + // in front of all admin http routes. For example, to set custom http + // headers + // httpAdminMiddleware: function(req,res,next) { + // // Set the X-Frame-Options header to limit where the editor + // // can be embedded + // //res.set('X-Frame-Options', 'sameorigin'); + // next(); + // }, + + // The following property can be used to pass custom options to the Express.js + // server used by Node-RED. For a full list of available options, refer + // to http://expressjs.com/en/api.html#app.settings.table + //httpServerOptions: { }, + + // The following property can be used to verify websocket connection attempts. + // This allows, for example, the HTTP request headers to be checked to ensure + // they include valid authentication information. + //webSocketNodeVerifyClient: function(info) { + // // 'info' has three properties: + // // - origin : the value in the Origin header + // // - req : the HTTP request + // // - secure : true if req.connection.authorized or req.connection.encrypted is set + // // + // // The function should return true if the connection should be accepted, false otherwise. + // // + // // Alternatively, if this function is defined to accept a second argument, callback, + // // it can be used to verify the client asynchronously. + // // The callback takes three arguments: + // // - result : boolean, whether to accept the connection or not + // // - code : if result is false, the HTTP error status to return + // // - reason: if result is false, the HTTP reason string to return + //}, + + // The following property can be used to seed Global Context with predefined + // values. This allows extra node modules to be made available with the + // Function node. + // For example, + // functionGlobalContext: { os:require('os') } + // can be accessed in a function block as: + // global.get("os") + + valueConvert: '%%valueConvert%%', + + functionGlobalContext: { + //'%%functionGlobalContext%%' + // os:require('os'), + // jfive:require("johnny-five"), + // j5board:require("johnny-five").Board({repl:false}) + }, + // `global.keys()` returns a list of all properties set in global context. + // This allows them to be displayed in the Context Sidebar within the editor. + // In some circumstances it is not desirable to expose them to the editor. The + // following property can be used to hide any property set in `functionGlobalContext` + // from being list by `global.keys()`. + // By default, the property is set to false to avoid accidental exposure of + // their values. Setting this to true will cause the keys to be listed. + exportGlobalContextKeys: false, + + + // Context Storage + // The following property can be used to enable context storage. The configuration + // provided here will enable file-based context that flushes to disk every 30 seconds. + // Refer to the documentation for further options: https://nodered.org/docs/api/context/ + // + //contextStorage: { + // default: { + // module:"localfilesystem" + // }, + //}, + + // The following property can be used to order the categories in the editor + // palette. If a node's category is not in the list, the category will get + // added to the end of the palette. + // If not set, the following default order is used: + //paletteCategories: ['subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'], + + // Configure the logging output + logging: { + // Only console logging is currently supported + console: { + // Level of logging to be recorded. Options are: + // fatal - only those errors which make the application unusable should be recorded + // error - record errors which are deemed fatal for a particular request + fatal errors + // warn - record problems which are non fatal + errors + fatal errors + // info - record information about the general running of the application + warn + error + fatal errors + // debug - record information which is more verbose than info + info + warn + error + fatal errors + // trace - record very detailed logging + debug + info + warn + error + fatal errors + // off - turn off all logging (doesn't affect metrics or audit) + level: "info", + // Whether or not to include metric events in the log output + metrics: false, + // Whether or not to include audit events in the log output + audit: false + } + }, + + // Customising the editor + editorTheme: { + projects: { + // To enable the Projects feature, set this value to true + enabled: '%%projectsEnabled%%' + } + }, + externalModules: { + palette: { + allowInstall: '%%palletmanagerEnabled%%' + } + } +};