test
This commit is contained in:
5
sambanas/.hadolint.yaml
Normal file
5
sambanas/.hadolint.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
ignored:
|
||||
- DL3003
|
||||
- DL3006
|
||||
- DL3018
|
||||
- DL3059
|
644
sambanas/CHANGELOG.md
Normal file
644
sambanas/CHANGELOG.md
Normal file
@@ -0,0 +1,644 @@
|
||||
# Changelog
|
||||
|
||||
## 12.5.0-nas [ Maintenance Mode ]
|
||||
|
||||
### ✨ Features
|
||||
|
||||
### 🚨 Important Notice Regarding SambaNas Addon Development
|
||||
|
||||
**SambaNas Addon is Now in Maintenance Mode**
|
||||
|
||||
This notice is to inform our users that the **SambaNas addon will now transition into maintenance mode.** This means that **no future features will be implemented** for this version of the addon. Our development efforts will be focused solely on providing **critical bug fixes** to ensure its continued stability for existing users.
|
||||
|
||||
**Introducing SambaNas2: The Future of Samba Integration**
|
||||
|
||||
We are excited to announce **SambaNas2**, the successor to the original SambaNas addon! SambaNas2 represents a **complete rewrite from the ground up, developed in Go with a brand new core.** This will bring significant improvements in performance, stability, and future extensibility.
|
||||
|
||||
**Current Status and Upcoming Beta Release**
|
||||
|
||||
SambaNas2 is currently in an **Alpha stage** of development. We are pleased to announce that a **public Beta version will be released in the coming weeks** and will be available through our beta channel.
|
||||
|
||||
We encourage users interested in the latest features and improvements to keep an eye out for the SambaNas2 beta release. Thank you for your continued support.
|
||||
|
||||
[Add our Hass.io BETA add-ons repository][beta-repository] to your Hass.io instance.
|
||||
|
||||
### 🩹 BugFix
|
||||
- Fix issue [#283](https://github.com/dianlight/hassio-addons/issues/283)
|
||||
- Missing Apparmor's permissions [#354](https://github.com/dianlight/hassio-addons/issues/354)
|
||||
|
||||
### 🏗 Chore
|
||||
- Update Based Image to 17.2.5 (Alpine 3.21.3, Samba 4.20.6)
|
||||
- [Full Changelog from official addon 12.3.2][changelog_12.5.0]
|
||||
- Add the ability to enable and disable trying to become a local master browser on a subnet
|
||||
- [Full Changelog from official addon 12.4.0][changelog_12.4.0]
|
||||
- (Skip) Add the ability to enable and disable specific shares, improving user control over folder access
|
||||
- [Full Changelog from official addon 12.3.3][changelog_12.3.3]
|
||||
- Enable Samba configurations to improve interoperability with Apple devices (Already applied)
|
||||
|
||||
[changelog_12.3.3]: https://github.com/home-assistant/addons/commit/be105fa07eedf5b29fc9ce9d0702914f5a8d6b03
|
||||
[changelog_12.4.0]: https://github.com/home-assistant/addons/pull/3877
|
||||
[changelog_12.5.0]: https://github.com/home-assistant/addons/commit/976afaf0206afb40d456a007cdc90b72f0943f13
|
||||
|
||||
## 12.3.2-nas1
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Build for armv7 arch Fix: [#288](https://github.com/dianlight/hassio-addons/issues/288)]
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- c018288 ⬆️ Update ha-mqtt-discoverable to v0.16.4
|
||||
- 9989ae7 ⬆️ Update humanize to v4.12.1
|
||||
- 93e576d ⬆️ Update ldez/gha-mjolnir action to v1.5.0
|
||||
- 4fcddcc ⬆️ Update pySMART to v1.4.1
|
||||
- 382ae4c ⬆️ Update psutil to v7
|
||||
- ed888dc ⬆️ Update ghcr.io/hassio-addons/base Docker tag to v17.2.1 (#327)
|
||||
- Better CI and Change scripts
|
||||
- Remove HDDTEMP for deprecation [#265](https://github.com/dianlight/hassio-addons/issues/265)
|
||||
- WSDD2. Use patch from openwrt to compile on GCC14 and 64bit
|
||||
|
||||
## 12.3.2-nas
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Allow use of samba multicast dns register
|
||||
- New `wsdd` option to enable/disable wsdd
|
||||
- New Sensor `Power` if you enable `hdd_idle_seconds` option in config
|
||||
- New Option `multi_channel` to Enable multi-channel in smb.conf [#262](https://github.com/dianlight/hassio-addons/issues/262)
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix Startup/Shutdown sequence [#252](https://github.com/dianlight/hassio-addons/issues/252)
|
||||
- Fix ACL miss on mixed-case disk's labels [#257](https://github.com/dianlight/hassio-addons/issues/257)
|
||||
- Fix passwords with spaces [#251](https://github.com/dianlight/hassio-addons/issues/251)
|
||||
- `bind_all_interfaces` option now act also on wsdd or wsdd2 daemon
|
||||
- Fix medialibrary can't use moredisks that contain a reserved word [#250](https://github.com/dianlight/hassio-addons/issues/250)
|
||||
- HD-Idle log monitoring. Fix [#240](https://github.com/dianlight/hassio-addons/issues/240)
|
||||
- Fix MQTT ID Changes Fix [#247](https://github.com/dianlight/hassio-addons/issues/247)
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- [Full Changelog from official addon 12.3.2][changelog_12.3.2]
|
||||
- Suppress benign idmap logged error
|
||||
- [Full Changelog from official addon 12.3.1][changelog_12.3.1]
|
||||
- Handle passwords with backslash correctly
|
||||
- [Full Changelog from official addon 12.3.0][changelog_12.3.0]
|
||||
- Upgrade Alpine Linux to 3.19 (Skipped)
|
||||
- Update Based Image to 16.3.6 (Alpine 3.20.3, Samba 4.19.9)
|
||||
- On trace log level the smb.conf and other datas are dumped in the ADDONS_CONFIG directory
|
||||
- Reduced smartd output
|
||||
- Update DOCS.md with more note on Power management use
|
||||
|
||||
### 👁️ Known Issue
|
||||
|
||||
- MQTT Entities sometime are not deleted on close
|
||||
|
||||
[changelog_12.3.0]: https://github.com/home-assistant/addons/pull/3456
|
||||
[changelog_12.3.1]: https://github.com/home-assistant/addons/pull/3508
|
||||
[changelog_12.3.2]: https://github.com/home-assistant/addons/pull/3704
|
||||
|
||||
## 12.2.0-nas2
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- New `bind_all_interfaces` option to allow work with pseudo ethernet devices. Support Tailscale may work for [#176](https://github.com/dianlight/hassio-addons/issues/176)
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Pin Python packages version on all platform. [#206](https://github.com/dianlight/hassio-addons/issues/206)
|
||||
- Change DOS charset to CP1253. [#204](https://github.com/dianlight/hassio-addons/issues/204)
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- Update Based Image to 15.0.6 (Alpine 3.19.1)
|
||||
|
||||
## 12.2.0-nas1
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- New `mqtt_nexgen_entities` option and scripts to enable new MQTT integration. This will be the default system for future integration is more efficent and use less resources but now is **Experimental**
|
||||
- `automount` now see also APFS drivers
|
||||
- Support reuse names from reserved share disabled (for [#188](https://github.com/dianlight/hassio-addons/issues/188))
|
||||
|
||||
### 💥 BREAKING CHANGE
|
||||
|
||||
- Removed deprecated `mqtt_use_legacy_entities` option and scripts.
|
||||
- Drop support for `armhf` and `i386`
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- 🐛 [Samba NAS] Auto mount fails afterupgrade to 12.1.0-nas [#181](https://github.com/dianlight/hassio-addons/issues/181)
|
||||
- SambaNAS - error after update /etc/s6-overlay/s6-rc.d/init-samba/run: line 47: /tmp/local_mount.json: No such file or directory [#194](https://github.com/dianlight/hassio-addons/issues/194)
|
||||
|
||||
## 12.2.0-nas
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Move addon config in `addons_config`
|
||||
- Homeassitant Automount also with different user in acl
|
||||
- ✨ [REQUEST] Support for APFS formatted hard drives [#184](https://github.com/dianlight/hassio-addons/issues/184) - Only ReadOnly for now
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- 🐛 [SambaNAS] Can't mount moredisks with label that contains a reserved word as substring [#188](https://github.com/dianlight/hassio-addons/issues/188)
|
||||
- 🐛 [sambanas] 0x80070032 The request is not supported [#182](https://github.com/dianlight/hassio-addons/issues/182)
|
||||
- 🐛 [SAMBA NAS] Unable to upload or rename files in external usb [#171](https://github.com/dianlight/hassio-addons/issues/171)
|
||||
- 🐛 [SAMBA NAS] Getting error 100093 when trying to add a file via SMB on an external exFat disk attached to the pi [#175](https://github.com/dianlight/hassio-addons/issues/175)
|
||||
|
||||
### 💥 BREAKING CHANGE
|
||||
|
||||
- **This is the last version with** `mqtt_use_legacy_entities`. Legacy implementation will be removed in next version.
|
||||
- "vfat" "msdos" "f2fs" "fuseblk" and "exfat" are now marked unsupported for timemachine.
|
||||
- Internal HA Storage Mount is done with a generated superuser
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- [Full Changelog from official addon 12.2.0][changelog_12.2.0]
|
||||
- Decrease Samba log level (Skipped. Loglevel is configurable)
|
||||
- Update Based Image to 15.0.3 (Alpine 3.19.0)
|
||||
|
||||
### 🧪 Experimental
|
||||
|
||||
- Rework on all MQTT client implementation. [In Progress]
|
||||
|
||||
[changelog_12.2.0]: https://github.com/home-assistant/addons/pull/3002
|
||||
|
||||
## 12.1.0-nas
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- [Full Changelog from official addon 12.1.0][changelog_12.1.0]
|
||||
- Use the new Home Assistant folder for the config share
|
||||
- Add support for accessing public add-on configurations
|
||||
- [Full Changelog from official addon 12.0.0][changelog_12.0.0]
|
||||
- Adjust location of Home Assistant config to match latest dev/beta Supervisor
|
||||
- [Full Changelog from official addon 11.0.0][changelog_11.0.0]
|
||||
- Add support for accessing public add-on configurations
|
||||
- Update Based Image to 14.3.2 (Alpine 3.18.4)
|
||||
- Adds HEALTCHECK support
|
||||
- [Full Changelog from official addon 10.0.2][changelog_10.0.2]
|
||||
- Already Implemented: Enable IPv6 ULA and IPv4 link-local addresses by default
|
||||
|
||||
[changelog_12.1.0]: https://github.com/home-assistant/addons/pull/3312
|
||||
[changelog_12.0.0]: https://github.com/home-assistant/addons/pull/3311
|
||||
[changelog_11.1.0]: https://github.com/home-assistant/addons/pull/3001
|
||||
[changelog_11.0.0]: https://github.com/home-assistant/addons/pull/3297
|
||||
[changelog_10.0.2]: https://github.com/home-assistant/addons/pull/3062
|
||||
[changelog_10.0.1]: https://github.com/home-assistant/addons/pull/2997
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix mount concurrency. Solve some issue on addon-restart. (try to resolve [#159](https://github.com/dianlight/hassio-addons/issues/159))
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Based Image 14.1.0 (Alpine 3.18.3)
|
||||
- Added recycle bin option option default is set to 'false' [cherry pick from PR#167] ([DOCS.md][docs])
|
||||
- Added mount options default is set to 'nosuid,relatime,noexec' [cherry pick from PR#167] ([DOCS.md][docs])
|
||||
- Added filter for reserved sharenames (config addons ssl share backup media) [cherry pick from PR#167]
|
||||
|
||||
## 10.0.2-nas4
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix mount bug for ha 2023.7.x without acl config.
|
||||
|
||||
## 10.0.2-nas3
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Add support of `acl.usage` to specify what scope of disk is, usefull for network storage mount in ha ([DOCS.md][docs])
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Always add docker network to whitelist - Try fix [#157](https://github.com/dianlight/hassio-addons/issues/157)
|
||||
- Correct cifs mount precedence. Try fix [[#159](https://github.com/dianlight/hassio-addons/issues/159)]
|
||||
|
||||
### 💥 BREAKING CHANGE
|
||||
|
||||
- Default `acl.timemachine` option now is set to `true`
|
||||
|
||||
## 10.0.2-nas2
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Read only users [[#141](https://github.com/dianlight/hassio-addons/issues/141)]
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix Bug [[#154](https://github.com/dianlight/hassio-addons/issues/154)]
|
||||
- Fix Bug [[#155](https://github.com/dianlight/hassio-addons/issues/155)]
|
||||
|
||||
## 10.0.2-nas1
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix a regression on MQTT status publish [#151](https://github.com/dianlight/hassio-addons/issues/151)
|
||||
|
||||
## 10.0.2-nas
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Suport new network disk mount to allow share to be visible by other addons ([DOCS.md][docs])
|
||||
- Dynamic frequency for updating disk sensor data. Minimizes CPU usage when disks are not in use.
|
||||
- Based Image 14.0.1 (Alpine 3.18)
|
||||
- Enable IPv6 ULA and IPv4 link-local addresses by default (from Samba Addon 10.0.2) [3062](https://github.com/home-assistant/addons/pull/3062)
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Partial Fix about MQTT cpu usage [#134](https://github.com/dianlight/hassio-addons/issues/134)
|
||||
|
||||
### 💥 BREAKING CHANGE
|
||||
|
||||
- Host Mount was **DEPRECATED** (DEPRECATED [DOCS.md][docs])
|
||||
- Minimal Homeassitant core supported version is now **2023.06.0**
|
||||
- The default behavior has been changed. Now the disk sensor integration is no longer turned on by default but turned off. See [DOCS.md][docs]
|
||||
|
||||
## 10.0.0-nas8
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Not OperatinSystem Allert (force EXIT)
|
||||
- Better support for "No Potection Mode"
|
||||
- [MQTT] support protected mode
|
||||
- [MQTT] Add Disk device
|
||||
- [MQTT] Add HD Temperature information
|
||||
- [MQTT] Report SMART Status (Read Error Rate, Reallocate Sectorer.... )
|
||||
- [MQTT] Corret Device->Partition "via_device"
|
||||
- Update documentation
|
||||
- Add option to enable SMART on supported drivers See [DOCS.md][docs]
|
||||
- Add [hd-idle](https://github.com/adelolmo/hd-idle) support FR [#34](https://github.com/dianlight/hassio-addons/issues/34)
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- [MQTT] Fix issue about % in fsuse_pct [#126](https://github.com/dianlight/hassio-addons/issues/126)]
|
||||
|
||||
### 💥 BREAKING CHANGE
|
||||
|
||||
- The addon now go in error if no `Home Assistant OS` is found on host. See [DOCS.md][docs]
|
||||
|
||||
## 10.0.0-nas7
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix issue about mount by id [#123](https://github.com/dianlight/hassio-addons/issues/123)
|
||||
- Fix issue about automount without external scripts [#124](https://github.com/dianlight/hassio-addons/issues/124)
|
||||
- Fix issue about mount hassos internal disks [#124](https://github.com/dianlight/hassio-addons/issues/124)
|
||||
|
||||
## 10.0.0-nas6
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix issue about missing ntfs3 module on amd64 architecture [#121](https://github.com/dianlight/hassio-addons/issues/121)
|
||||
- Fix missing libcap for wsdd2
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Add support for btrfs fs
|
||||
- Add support for xfs fs
|
||||
|
||||
## 10.0.0-nas5
|
||||
|
||||
### 💥 BREAKING CHANGE 🆘
|
||||
|
||||
- Disk referenced by `id` that have a valid label are mounted and shared with label name.
|
||||
- The automount feature is enabled by default. See [DOCS.md][docs]
|
||||
- Backport [nas4]: Remove FUSE ntfs3g and exFat support (was broken so no one will use!).
|
||||
- MQTT status message was refactored and report also fstype and disk iostat. If you need the old system use `mqtt_use_legacy_entities` option [DOCS.md][docs]
|
||||
- New default config with automount and new mqtt entity system
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Disk and Partitions referenced by `id` now are mounted and shared by label name if exists **dedupl not work**
|
||||
- Disk labels with ::space:: are now supported
|
||||
- Disk summary with share names
|
||||
- Backport [nas4]: Add support for NTFS3 fs 🎉 🎉 🚨🎉 🎉 (EXPERIMENTAL [DOCS.md][docs])) 🎉 🎉 🎉
|
||||
- Backport [nas4]: Add support for exFat fs 🎉 🎉 🚨🎉 🎉 (EXPERIMENTAL [DOCS.md][docs])) 🎉 🎉 🎉
|
||||
- Backport [nas4]: Add new MQTT report entity system based on device not on mount path and iostat [DOCS.md][docs]
|
||||
- Backport [nas4]: Add Automount support for all partition's with labels [DOCS.md][docs]
|
||||
- Backport [nas4]: Support Partition with spaces ISSUE [#118](https://github.com/dianlight/hassio-addons/issues/118)
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- Backport [nas4]: Migrate to [Home Assistant Community Add-on: Base Images](https://github.com/hassio-addons/addon-base) 13.0.0
|
||||
- Backport [nas4]: Migrate to new s6-rc system
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Backport [nas4]: Fix error without MQTT server BUG [#116](https://github.com/dianlight/hassio-addons/issues/116)
|
||||
|
||||
## 10.0.0-nas4 [Restricted release]
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Add support for NTFS3 fs 🎉 🎉 🚨🎉 🎉 (EXPERIMENTAL [DOCS.md][docs])) 🎉 🎉 🎉
|
||||
- Add support for exFat fs 🎉 🎉 🚨🎉 🎉 (EXPERIMENTAL [DOCS.md][docs])) 🎉 🎉 🎉
|
||||
- Add new MQTT report entity system based on device not on mount path and iostat [DOCS.md][docs]
|
||||
- Add Automount support for all partition's with labels [DOCS.md][docs]
|
||||
- Support Partition with spaces ISSUE [#118](https://github.com/dianlight/hassio-addons/issues/118)
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- Migrate to [Home Assistant Community Add-on: Base Images](https://github.com/hassio-addons/addon-base) 13.0.0
|
||||
- Migrate to new s6-rc system
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix error without MQTT server BUG [#116](https://github.com/dianlight/hassio-addons/issues/116)
|
||||
|
||||
### 💥 BREAKING CHANGE
|
||||
|
||||
- The automount feature is enabled by default. See [DOCS.md][docs]
|
||||
- Remove FUSE ntfs3g and exFat support (was broken so no one will use!).
|
||||
- MQTT status message was refactored and report also fstype and disk iostat. If you need the old system use `mqtt_use_legacy_entities` option [DOCS.md][docs]
|
||||
- New default config with automount and new mqtt entity system
|
||||
|
||||
## 10.0.0-nas3
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Add `loglevel` option.
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix Share Name BUG [#106](https://github.com/dianlight/hassio-addons/issues/106)
|
||||
|
||||
### 💥 BREAKING CHANGE
|
||||
|
||||
There is a new algorithm for creating the SHARE name. Therefore the name of the exposed shares could change.
|
||||
|
||||
## 10.0.0-nas2
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix ACL Bug [#98](https://github.com/dianlight/hassio-addons/issues/98)
|
||||
|
||||
## 10.0.0-nas1
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fix Host Unmountig Bug [#94](https://github.com/dianlight/hassio-addons/issues/94)
|
||||
|
||||
## 10.0.0-nas
|
||||
|
||||
### 💥 BREAKING CHANGE
|
||||
|
||||
- Don't mangle filenames: By default, Samba mangles filenames with special characters to ensure
|
||||
compatibility with really old versions of Windows which have a very limited charset for filenames. The add-on no longer does this as modern operating
|
||||
systems do not have these restrictions.
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Option to use WSDD2 over WSDD (see [DOCS.md][docs])
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- Refactor all MQTT HA integration
|
||||
- Refactor root mount point selection ( no more pollution in /media if you don't use medialibrary )
|
||||
- Refactor Docker composition
|
||||
- [Full Changelog from official addon 10.0.0][changelog_10.0.0]
|
||||
- Don't mangle filenames (fixes [#2541](https://github.com/home-assistant/addons/issues/2541))
|
||||
|
||||
[changelog_10.0.0]: https://github.com/home-assistant/addons/pull/2545
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Autodiscovery (WSDD2) interface respect configuration
|
||||
|
||||
## 9.7.0-nas2
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Merged PR #85 by @grischard - Fix Bug [#84](https://github.com/dianlight/hassio-addons/issues/84)
|
||||
|
||||
## 9.7.0-nas1
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Add wsdd for Windows10/11 autodiscovery
|
||||
- Support Enabline/Disabling Shares (based on PR#72 by @Uneo7 | Issue #24)
|
||||
- Support for different users on shares (Issue #19)
|
||||
- Interface options ( based on the idea of lmagyar/homeassistant-addon-samba-interface addon )
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- Upgrade Alpine Linux to 3.16
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- AVAHI Support hostname with dot
|
||||
|
||||
## 9.7.0-nas
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Add btrfs support (PR #75 By @fAuernigg)
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Change startup to system (PR #81 By @marciogranzotto)
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- [Full Changelog from official addon 9.5.1][changelog_9.7.0]
|
||||
- Upgrade Alpine Linux to 3.15
|
||||
- Sign add-on with Codenotary Community Attestation Service (CAS)
|
||||
- [Full Changelog from official addon 9.5.0][changelog_9.6.1]
|
||||
- Remove lo from interface list
|
||||
- Exit with error if there are no supported interfaces to run Samba on
|
||||
- [Full Changelog from official addon 9.6.0][changelog_9.6.0]
|
||||
- Run on all supported interfaces
|
||||
|
||||
[changelog_9.7.0]: https://github.com/home-assistant/addons/pull/2070
|
||||
[changelog_9.6.1]: https://github.com/home-assistant/addons/pull/2031
|
||||
[changelog_9.6.0]: https://github.com/home-assistant/addons/pull/2023
|
||||
|
||||
## 9.5.1-nas4
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Lovely initial Banner!
|
||||
- New Option `available_disks_log` to turn on/off the list of available Labeled disk in log
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fixed Bug #60 ( No access after update to Samba NAS 9.5.1-nas3 )
|
||||
|
||||
## 9.5.1-nas3
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- List all available Labeled and Id disks on startup. Useful for configuration
|
||||
- Support mount by disk Id as label (Format `id:<diskid>`)
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fixed Bug #58 ( Latest update doesn't allow multiple mounts )
|
||||
|
||||
## 9.5.1-nas2
|
||||
|
||||
### 🩹 BugFix
|
||||
|
||||
- Fixed Bug #54 ( MQTT Available missing for some disks )
|
||||
|
||||
## 9.5.1-nas1
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- 🎉 🎉 🚨🎉 🎉 Support to Host Mount (EXPERIMENTAL [DOCS.md][docs])) 🎉 🎉 🎉
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- Remove Private Key from log
|
||||
|
||||
## 9.5.1-nas
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- 🎉 🎉 🚨🎉 🎉 Support to Host Mount (EXPERIMENTAL [DOCS.md][docs]) 🎉 🎉 🎉
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Correct and update DOCS.md
|
||||
|
||||
### 🏗 Chore
|
||||
|
||||
- [Full Changelog from official addon 9.5.1][changelog_9.5.1]
|
||||
- [Full Changelog from official addon 9.5.0][changelog_9.5.0]
|
||||
- [Full Changelog from official addon 9.4.0][changelog_9.4.0]
|
||||
- Update options schema for passwords (Official Addon 9.3.1)
|
||||
|
||||
[changelog_9.5.1]: https://github.com/home-assistant/addons/pull/2070
|
||||
[changelog_9.5.0]: https://github.com/home-assistant/addons/pull/2031
|
||||
[changelog_9.4.0]: https://github.com/home-assistant/addons/pull/2023
|
||||
[changelog_9.3.1]: https://github.com/home-assistant/hassio-addons/pull/1569
|
||||
|
||||
## 9.3.0-nas8
|
||||
|
||||
- chore: Support new Supervisor/Hardware ( remov dev\_ trick )
|
||||
- chore: Apparmor config optimization for broadcast.
|
||||
- fix: remove double % sign on HA report. (Bug #38)
|
||||
|
||||
## 9.3.0-nas7
|
||||
|
||||
- Fix: config style for new Supervisor/Hardware
|
||||
- Added Apparmor config (PR #36 by @alexbelgium) (Bug #35)
|
||||
|
||||
## 9.3.0-nas6
|
||||
|
||||
- Fix: Ignore MQTT service if the given HA url is invalid.
|
||||
|
||||
## 9.3.0-nas5
|
||||
|
||||
- Disable MQTT integration in no MQTT service is found
|
||||
|
||||
## 9.3.0-nas4
|
||||
|
||||
- Remove unnecessary devicetree request (Bug #13)
|
||||
|
||||
## 9.3.0-nas3
|
||||
|
||||
- Fix idmap range not specified warning in log
|
||||
- MQTT sensor improvement:
|
||||
- Option to disable MQTT integration
|
||||
- Options to control MQTT autodiscovery
|
||||
- Added device data to HA discovery messages
|
||||
- Better Device\Sensors tree
|
||||
- Autoremove discovery on disk unmount
|
||||
- Fix MQTT unique_id to allow HA interface management
|
||||
|
||||
## 9.3.0-nas2
|
||||
|
||||
- Fix autobuild script for empty directories
|
||||
- Removed unused debug.
|
||||
|
||||
## 9.3.0-nas1
|
||||
|
||||
- Bugfixes
|
||||
- Expose NAS disk status on MQTT (60s refresh)
|
||||
- Update Samba to 4.12.7
|
||||
|
||||
## 9.3.0-nas
|
||||
|
||||
- [Full Changelog from official addon][changelog_9.3.0]
|
||||
- Support new media folder
|
||||
- Update Samba to 4.12.6
|
||||
- Upgrade Alpine Linux to 3.12
|
||||
|
||||
[changelog_9.3.0]: https://github.com/home-assistant/hassio-addons/pull/1569
|
||||
|
||||
## 9.2.0-nas
|
||||
|
||||
- [Based on samba addon 9.2.0]
|
||||
- Pin base image version
|
||||
- Rewrite add-on onto S6 Overlay
|
||||
- Use default configuration location
|
||||
- Add support for running in compatibility mode (SMB1/NT1)
|
||||
- Add dummy files to reduce number of errors/warnings in log output
|
||||
- Allow IPv6 link-local hosts by default, consistent with IPv4
|
||||
|
||||
## 9.0-nas
|
||||
|
||||
### Added
|
||||
|
||||
- Add devfs support
|
||||
- Add Time Machine support ( share disk can be used for Time Machine backup )
|
||||
- Add disk/by-label automount and autoshare
|
||||
- Add mDNS service registration
|
||||
|
||||
### Security
|
||||
|
||||
- Elevated minimal supported protocol to SMB2
|
||||
|
||||
### Changed
|
||||
|
||||
- [Based on samba addon 9.0](https://github.com/home-assistant/hassio-addons/tree/master/samba)
|
||||
|
||||
## 9.0
|
||||
|
||||
- New option `veto_files` to limit writing of specified files to the share
|
||||
|
||||
## 8.3
|
||||
|
||||
- Fixes a bug in warning log message, causing start failure
|
||||
- Minor code cleanups
|
||||
|
||||
## 8.2
|
||||
|
||||
- Update from bash to bashio
|
||||
|
||||
## 8.1
|
||||
|
||||
- Update Samba to version 4.8.8
|
||||
|
||||
## 8.0
|
||||
|
||||
- Fix access to /backup
|
||||
|
||||
## 7.0
|
||||
|
||||
- Remove guest access
|
||||
- Cleanup structure
|
||||
- Use hostname for samba device name
|
||||
|
||||
## 6.0
|
||||
|
||||
- Enable ntlm auth for Windows10
|
||||
|
||||
## 5.0
|
||||
|
||||
- Update Samba to version 4.8.4
|
||||
|
||||
## 4.1
|
||||
|
||||
- Bugfix sed command
|
||||
|
||||
## 4.0
|
||||
|
||||
- New option `allow_hosts` to limit access
|
||||
|
||||
## 3.0
|
||||
|
||||
- Update base image
|
||||
|
||||
[docs]: https://github.com/dianlight/hassio-addons/blob/master/sambanas/DOCS.md
|
411
sambanas/DOCS.md
Normal file
411
sambanas/DOCS.md
Normal file
@@ -0,0 +1,411 @@
|
||||
# Home Assistant Add-on: Samba NAS share
|
||||
|
||||
# 📰 Important Notice Regarding SambaNas Addon Development
|
||||
|
||||
**SambaNas Addon is Now in Maintenance Mode**
|
||||
|
||||
This notice is to inform our users that the **SambaNas addon will now transition into maintenance mode.** This means that **no future features will be implemented** for this version of the addon. Our development efforts will be focused solely on providing **critical bug fixes** to ensure its continued stability for existing users.
|
||||
|
||||
**Introducing SambaNas2: The Future of Samba Integration**
|
||||
|
||||
We are excited to announce **SambaNas2**, the successor to the original SambaNas addon! SambaNas2 represents a **complete rewrite from the ground up, developed in Go with a brand new core.** This will bring significant improvements in performance, stability, and future extensibility.
|
||||
|
||||
**Current Status and Upcoming Beta Release**
|
||||
|
||||
SambaNas2 is currently in an **Alpha stage** of development. We are pleased to announce that a **public Beta version will be released in the coming weeks** and will be available through our beta channel.
|
||||
|
||||
We encourage users interested in the latest features and improvements to keep an eye out for the SambaNas2 beta release. Thank you for your continued support.
|
||||
|
||||
|
||||
## 🚨 Important Note 🚨
|
||||
|
||||
This addon has been designed, built and tested to work with HAOS (Homeassistant Operating System). The use in other types of installations is not recommended and useless as other solutions given by the host can be used.
|
||||
|
||||
### Using it on a different operating system leads to the error at startup. I apologize to all the advanced users who are using it on different OSes but I manage the addon in my spare time and instead of doing something useful lately I'm only replying to people who don't read the documentation. "This is the meaning of life"
|
||||
|
||||
## Installation
|
||||
|
||||
Follow these steps to get the add-on installed on your system:
|
||||
|
||||
1. Navigate in your Home Assistant frontend to **Supervisor** -> **Add-on Store**.
|
||||
2. Find the "Samba NAS share" add-on and click it.
|
||||
3. Click on the "INSTALL" button.
|
||||
|
||||
## How to use
|
||||
|
||||
1. In the configuration section, set a username and password.
|
||||
2. Review the enabled shares. Disable any you do not plan to use. Shares can be re-enabled later if needed.
|
||||
|
||||
## Connection
|
||||
|
||||
If you are on Windows you use `\\<IP_ADDRESS>\`, if you are on MacOS you use `smb://<IP_ADDRESS>` to connect to the shares.
|
||||
|
||||
This addon exposes the following directories over smb (samba):
|
||||
|
||||
| Directory | Description |
|
||||
| --------------- | ------------------------------------------------------------------------ |
|
||||
| `addons` | This is for your local add-ons. |
|
||||
| `backup` | This is for your snapshots. |
|
||||
| `config` | This is for your Home Assistant configuration. |
|
||||
| `addon_configs` | This is for your Addons base configuration directory |
|
||||
| `media` | This is for local media files. |
|
||||
| `share` | This is for your data that is shared between add-ons and Home Assistant. |
|
||||
| `ssl` | This is for your SSL certificates. |
|
||||
|
||||
## Configuration
|
||||
|
||||
This is an example of a configuration. **_DO NOT USE_** without making the necessary changes especially for the username, password, secret and moredisk part.
|
||||
Fields between `<` and `>` indicate values that are omitted and need to be changed.
|
||||
|
||||
```yaml
|
||||
workgroup: WORKGROUP
|
||||
local_master: true
|
||||
username: Hassio
|
||||
password: "<Your secret password>"
|
||||
allow_hosts:
|
||||
- 10.0.0.0/8
|
||||
- 172.16.0.0/12
|
||||
- 192.168.0.0/16
|
||||
- 169.254.0.0/16
|
||||
- fe80::/10
|
||||
- fc00::/7
|
||||
automount: true
|
||||
moredisks:
|
||||
- "<Partition's Label>"
|
||||
- "id:<Partition uuid>"
|
||||
mountoptions: "nosuid,relatime,noexec"
|
||||
veto_files:
|
||||
- "._*"
|
||||
- ".DS_Store"
|
||||
- Thumbs.db
|
||||
compatibility_mode: false
|
||||
recyle_bin_enabled: false
|
||||
available_disks_log: true
|
||||
wsdd: true
|
||||
wsdd2: false
|
||||
medialibrary:
|
||||
enable: true
|
||||
other_users:
|
||||
- username: backupuser
|
||||
password: "<backupuser secret password>"
|
||||
- username: secureuser
|
||||
password: "<secureuser secret password>"
|
||||
acl:
|
||||
- share: config
|
||||
disabled: true
|
||||
- share: backup
|
||||
disabled: false
|
||||
users:
|
||||
- backupuser
|
||||
- share: ssl
|
||||
users:
|
||||
- secureuser
|
||||
```
|
||||
|
||||
### Option: `workgroup` (required)
|
||||
|
||||
Change WORKGROUP to reflect your network needs.
|
||||
|
||||
### Option: `local_master` (required)
|
||||
|
||||
Enable to try and become a local master browser on a subnet.
|
||||
|
||||
### Option: `username` (required)
|
||||
|
||||
The username you would like to use to authenticate with the Samba server.
|
||||
|
||||
### Option: `password` (required)
|
||||
|
||||
The password that goes with the username configured for authentication.
|
||||
|
||||
### Option: `allow_hosts` (required)
|
||||
|
||||
List of hosts/networks allowed to access the shared folders.
|
||||
|
||||
### Option `automount` (optional)
|
||||
|
||||
**_Protection Mode must be disabled to allow this function_**
|
||||
Automatic mount and expose all labeled disk.
|
||||
|
||||
Defaults to `true`.
|
||||
|
||||
### Option: `moredisks` (optional)
|
||||
|
||||
**_Protection Mode must be disabled to allow this function_**
|
||||
List of disks or partitions label to search and share. It is also possible to use the disk id if you prepend the name with `id:` (WARN: write id prefix in lowercase only!)
|
||||
|
||||
The following Fs are supported:
|
||||
|
||||
- [x] ext3
|
||||
- [x] ext2
|
||||
- [x] ext4
|
||||
- [x] squashfs
|
||||
- [x] vfat --> **_NOTE: ACL are not supported so no TimeMachine compatibility_**
|
||||
- [x] msdos --> **_NOTE: ACL are not supported so no TimeMachine compatibility_**
|
||||
- [x] f2fs --> **_NOTE: ACL are not supported so no TimeMachine compatibility_**
|
||||
- [x] exFat --> **_NOTE: Experimental with exFat kernel driver_**
|
||||
- [x] ntfs --> **_NOTE: Experimental with ntfs3 kernel driver. Not available on some architectures_**
|
||||
- [x] brtfs
|
||||
- [x] xfs
|
||||
- [x] apfs --> **_NODE: Very Experimental. ReadOnly and referenced only by id not label. Mount options are not supported_**
|
||||
|
||||
### Option `mountoptions` (required)
|
||||
Allows setting of mount options.
|
||||
|
||||
**_Protection Mode must be disabled to allow this function_**
|
||||
Defaults to 'nosuid,relatime,noexec'
|
||||
|
||||
### Option `available_disks_log` (optional)
|
||||
|
||||
Enable the log of found labeled disk. Usefull for initial configuration.
|
||||
|
||||
### Option: `log_level` (optional)
|
||||
|
||||
The log_level option controls the level of log output by the addon and can be changed to be more or less verbose, which might be useful when you are dealing with an unknown issue. Possible values are:
|
||||
|
||||
- trace: Show every detail, like all called internal functions.
|
||||
- debug: Shows detailed debug information.
|
||||
- info: Normal (usually) interesting events.
|
||||
- warning: Exceptional occurrences that are not errors.
|
||||
- error: Runtime errors that do not require immediate action.
|
||||
- fatal: Something went terribly wrong. Add-on becomes unusable.
|
||||
|
||||
Please note that each level automatically includes log messages from a more severe level, e.g., debug also shows info messages. By default, the log_level is set to info, which is the recommended setting unless you are troubleshooting.
|
||||
|
||||
### Option: `medialibrary` (optional) **_Exteprimental_**
|
||||
|
||||
Enable the visibility of `moredisk` on /media path.
|
||||
|
||||
_Starting from Homeassistant 2023.6.0 the addon use the 'mount' supervisor feature. So you don't need the ssh key anymore._
|
||||
|
||||
**WARNING: The feature is considered experimental and may cause problems or data loss.**
|
||||
|
||||
#### Option: `enable` (optional)
|
||||
|
||||
Enable/Disable host mounting option.
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
### Option: `recyle_bin_enabled` (optional)
|
||||
|
||||
Setting this option to `true` will enable recycle bin functions
|
||||
on the Samba add-on. ***Check 'veto_files' as could be blocked by '._*'.***
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
#### Option: `ssh_private_key` (optional) **_Deprecated_**
|
||||
|
||||
The **_PRIVATE_** key for SSH access to the host on port 22222.
|
||||
|
||||
Enables mounting of `moredisk` by the host and not by the container.
|
||||
|
||||
NOTE<sup>1</sup>: It works only and only on HassOS on other hosts it is not tested and most likely it does not work.
|
||||
|
||||
NOTE<sup>2</sup>: It is necessary to enable the access to the SSH port 22222 of the host. Read the HassOS [Developers Documentation](https://developers.home-assistant.io/docs/operating-system/debugging/#home-assistant-operating-system) or use the [Configutarion Addon](https://community.home-assistant.io/t/add-on-hassos-ssh-port-22222-configurator/264109).
|
||||
|
||||
NOTE<sup>3</sup>: It is necessary to pass the SSH private key for root access to the host. Be sure to use secrets files to protect the key from people who don't have access to it.
|
||||
|
||||
NOTE<sup>4</sup>: If the disk in the "Media Browser" is seen empty try restarting Homeassitant.
|
||||
|
||||
|
||||
### Option: `veto_files` (optional)
|
||||
|
||||
List of files that are neither visible nor accessible. Useful to stop clients
|
||||
from littering the share with temporary hidden files
|
||||
(e.g., macOS `.DS_Store` or Windows `Thumbs.db` files)
|
||||
|
||||
### Option: `other_users` (optional) (**advanced users only**)
|
||||
|
||||
The list of additional user for the addon. See `acl` option for enable the access to the shares.
|
||||
|
||||
#### Option: `username` (required)
|
||||
|
||||
The username you would like to use to authenticate with.
|
||||
|
||||
#### Option: `password` (required)
|
||||
|
||||
The password that goes with the username configured for authentication.
|
||||
|
||||
### Option: `acl` (optional) (**advanced users only**)
|
||||
|
||||
The Access Control List for shares. This is an advanced parameter to control every single share.
|
||||
The format is an array of share object with this subparameters
|
||||
|
||||
#### Option: `share` (required)
|
||||
|
||||
The share name.
|
||||
|
||||
#### Option: `disabled` (optional)
|
||||
|
||||
If the disabled flag is true the share is not exported
|
||||
|
||||
Defaults to `false`
|
||||
|
||||
#### Option: `users` (optional)
|
||||
|
||||
The list of users with access to share. If omitted the main user is used. See `other_users` option
|
||||
|
||||
Defaults to `master user`
|
||||
|
||||
#### Option: `ro_users` (optional)
|
||||
|
||||
The list of users with readonly access to share.
|
||||
|
||||
Defaults to none
|
||||
|
||||
#### Option: `timemachine` (optional)
|
||||
|
||||
If is true the share is exposed with timechine compatible setting.
|
||||
|
||||
Defaults to `false` for internal share, `true` forn extra disks.
|
||||
|
||||
### Option: `usage` (optional) (**valid only for external disks**)
|
||||
|
||||
Set the scope of the disk, usefull for ha network storage mount. Valid values are `media`,`backup`,`share`
|
||||
|
||||
Defaults to `media` for external disks if `medialibray` is enabled.
|
||||
|
||||
|
||||
### Option: `interfaces` (optional) (**advanced users only**)
|
||||
|
||||
The network interfaces Samba should listen on for incoming connections.
|
||||
|
||||
This option should only be used in advanced cases. In general, setting this option is not needed.
|
||||
|
||||
If omitted Samba will listen on all supported interfaces of Home Assistant (see > ha network info), but if there are no supported interfaces, Samba will exit with an error.
|
||||
|
||||
**Note**: Samba needs at least one non-loopback, non-ipv6, local interface to listen on and become browser on it. Without it, it works, but reloads it's interfaces in an infinite loop forever in each 10 seconds to check, whether a non-loopback, non-ipv6, local interface is added. This reload will fill the log file with infinite number of entries like added interface lo ip=::1 bcast= netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff.
|
||||
|
||||
### Option: `bind_all_interfaces` (optional)
|
||||
|
||||
Force Samba to bind on all network interface.
|
||||
This is usefull for pseudo-ethernet devices like TailScale
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
### Option: `compatibility_mode` (optional)
|
||||
|
||||
Setting this option to `true` will enable old legacy Samba protocols
|
||||
on the Samba add-on. This might solve issues with some clients that cannot
|
||||
handle the newer protocols, however, it lowers security. Only use this
|
||||
when you absolutely need it and understand the possible consequences.
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
### Option: `wsdd`
|
||||
|
||||
Setting this option to `true` will enable the use of wsdd over internal samba system.
|
||||
|
||||
Defaults to `true`.
|
||||
|
||||
### Option: `wsdd2` (optional) (**advanced users only**)
|
||||
|
||||
Setting this option to `true` will enable the use of wsdd2 over wsdd. Set to true if you have trouble to see the disk on Windows 11+
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
### Option: `hdd_idle_seconds` (optional) (**Use only if your disks never spind down**)
|
||||
|
||||
Idle time in seconds for all disks. Setting this value to 0 will never spin down the disk(s).
|
||||
|
||||
**NOTE<sup>1</sup>**: Depending on your environment host system can take up to **10minutes** to unlock used file on disk so setting to a low number like 10 don't garantee that the disk go on sleep after 10s from last access. Sometime you need to wait 10 or 15 minutes.
|
||||
**NOTE<sup>2</sup>**: If you use `mqtt_nexgen_entities` also enable a new sensor for power disk status.
|
||||
|
||||
Defaults to hd-idle demon not being used at all.
|
||||
|
||||
### Option: `enable_smart` (optional)
|
||||
|
||||
Enable SMART on all disks, enable automatic offline testing every four hours, and enable autosaving of SMART Attributes.
|
||||
|
||||
Defaults to `true`.
|
||||
|
||||
### Option: `multi_channel` (optional) **_Exteprimental_**
|
||||
|
||||
Samba 4.4.0 adds *experimental* support for SMB3 Multi-Channel.
|
||||
Multi-Channel is an SMB3 protocol feature that allows the client
|
||||
to bind multiple transport connections into one authenticated
|
||||
SMB session. This allows for increased fault tolerance and
|
||||
throughput. The client chooses transport connections as reported
|
||||
by the server and also chooses over which of the bound transport
|
||||
connections to send traffic. I/O operations for a given file
|
||||
handle can span multiple network connections this way.
|
||||
An SMB multi-channel session will be valid as long as at least
|
||||
one of its channels are up.
|
||||
|
||||
Defaults to `false`
|
||||
|
||||
### Option: `mqtt_enable` (optional)
|
||||
|
||||
Setting this option to `true` will enable the use of mqtt to send disks status data.
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
### Option: `mqtt_nexgen_entities` (optional)
|
||||
|
||||
Setting this option to `true` will expose mqtt new entities. This is a refactor that allow to use less CPU.
|
||||
|
||||
**NOTE<sup>1</sup>**: If your HDD newer spindown please set `hdd_idle_seconds`.
|
||||
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
### Option: `mqtt_host` (optional)
|
||||
|
||||
If using an external mqtt broker, the hostname/URL of the broker. See [MQTT Status Notifications](https://github.com/thomasmauerer/hassio-addons/blob/master/samba-backup/DOCS.md#mqtt-status-notifications) for additional infos.
|
||||
|
||||
**Note**: _Do not set this option if you want to use the (on-device) Mosquitto broker addon._
|
||||
|
||||
### Option: `mqtt_username` (optional)
|
||||
|
||||
If using an external mqtt broker, the username to authenticate with the broker.
|
||||
|
||||
### Option: `mqtt_password` (optional)
|
||||
|
||||
If using an external mqtt broker, the password to authenticate with the broker.
|
||||
|
||||
### Option: `mqtt_port` (optional)
|
||||
|
||||
If using an external mqtt broker, the port of the broker. If not specified the default port 1883 will be used.
|
||||
|
||||
### Option: `mqtt_topic` (optional)
|
||||
|
||||
The topic to which status updates will be published. You can only control the root topic with this option, the subtopic is fixed!
|
||||
|
||||
_Example_: sambanas/status: "sambanas" is the root topic, whereas "status" is the subtopic.
|
||||
|
||||
### Option: `autodiscovery` (**advanced users only**)
|
||||
|
||||
#### Option: `disable_discovery` (optional)
|
||||
|
||||
Setting this option to `true` will disable the sending of Auto Discovery MQTT messages. You need to configure MQTT sensors manually
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
#### Option: `disable_persistent` (optional)
|
||||
|
||||
Setting this option to `true` will disable the mark MQTT discovery messages as persistents.
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
#### Option: `disable_autoremove` (optional)
|
||||
|
||||
Setting this option to `true` will disable the delete of MQTT discovery messages when addon stop.
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
## Support
|
||||
|
||||
### Do you like the Addon?
|
||||
<a href="https://www.buymeacoffee.com/ypKZ2I0"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=ypKZ2I0&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff" /></a>
|
||||
|
||||
### Common problems
|
||||
|
||||
- **_The disk does not mount_** : check that the Label of the partition of the disk you want to mount is case-sensitive with the label indicated in the `moredisk` parameter.
|
||||
|
||||
- **_In the menu `Media Browser` the folder with the name of the disk is empty_** : it happens when the homeassistant server starts before the add-on. Restart HomeAssitant from menu `Configuration->Server Controls->Server management -> RESTART`
|
||||
|
||||
In case you've found a bug, please [open an issue on our GitHub][issue].
|
||||
|
||||
[issue]: https://github.com/dianlight/hassio-addons/issues
|
||||
[reddit]: https://reddit.com/r/homeassistant
|
||||
[repository]: https://github.com/dianlight/hassio-addons
|
150
sambanas/Dockerfile
Normal file
150
sambanas/Dockerfile
Normal file
@@ -0,0 +1,150 @@
|
||||
ARG BUILD_FROM
|
||||
ARG BUILD_DATE
|
||||
ARG BUILD_DESCRIPTION
|
||||
ARG BUILD_NAME
|
||||
ARG BUILD_REF
|
||||
ARG BUILD_REPOSITORY
|
||||
ARG BUILD_VERSION
|
||||
|
||||
#ARG HDDTEMP_VERSION
|
||||
|
||||
# hadolint ignore=DL3006
|
||||
FROM $BUILD_FROM as builder
|
||||
|
||||
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]
|
||||
RUN apk add --no-cache make \
|
||||
gcc libc-dev linux-headers build-base autoconf automake git \
|
||||
python3-dev musl-dev poetry go lsblk eudev
|
||||
|
||||
ARG BUILD_ARCH
|
||||
|
||||
RUN cd / && wget -q -O - "https://github.com/Netgear/wsdd2/archive/refs/heads/master.tar.gz" | tar zxvf - \
|
||||
&& cd wsdd2-master \
|
||||
&& wget -q -O - https://raw.githubusercontent.com/openwrt/packages/refs/heads/master/net/wsdd2/patches/010-gcc14.patch | patch -p1 \
|
||||
&& make
|
||||
|
||||
COPY rootfs /
|
||||
RUN cd /usr/local/bin/ && \
|
||||
if [ "$BUILD_ARCH" == "armv7" ]; then \
|
||||
export PIP_NO_BINARY="pyyaml" ; \
|
||||
fi && \
|
||||
poetry install
|
||||
|
||||
# hadolint ignore=DL3006
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
# Set shell
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
# Environment variables
|
||||
ENV \
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI=true \
|
||||
HOME="/root" \
|
||||
LANG="C.UTF-8" \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
||||
PIP_FIND_LINKS=https://wheels.home-assistant.io/musllinux/ \
|
||||
PIP_NO_CACHE_DIR=1 \
|
||||
PIP_PREFER_BINARY=1 \
|
||||
PS1="$(whoami)@$(hostname):$(pwd)$ " \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \
|
||||
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
||||
S6_CMD_WAIT_FOR_SERVICES=1 \
|
||||
YARN_HTTP_TIMEOUT=1000000 \
|
||||
TERM="xterm-256color"
|
||||
|
||||
# Wait more time to allow gracefull shutdown
|
||||
ENV S6_KILL_GRACETIME=30000
|
||||
ENV S6_SYNC_DISKS=1
|
||||
|
||||
# Setup base
|
||||
ARG BUILD_ARCH
|
||||
ARG CLI_VERSION
|
||||
RUN apk add --no-cache \
|
||||
samba-common-tools \
|
||||
samba-server \
|
||||
samba-client \
|
||||
dbus \
|
||||
exfatprogs \
|
||||
btrfs-progs \
|
||||
xfsprogs \
|
||||
udev \
|
||||
eudev \
|
||||
hwids-udev \
|
||||
device-mapper-udev \
|
||||
attr \
|
||||
e2fsprogs \
|
||||
util-linux \
|
||||
e2fsprogs-extra \
|
||||
avahi \
|
||||
avahi-compat-libdns_sd \
|
||||
avahi-tools \
|
||||
curl \
|
||||
mosquitto-clients \
|
||||
openssh-client \
|
||||
findmnt \
|
||||
ntfs-3g-progs \
|
||||
sysstat \
|
||||
hdparm \
|
||||
smartmontools \
|
||||
wsdd \
|
||||
udisks2 \
|
||||
libcap \
|
||||
hd-idle \
|
||||
fuse3 \
|
||||
py3-pip \
|
||||
pipx \
|
||||
poetry \
|
||||
lsblk \
|
||||
socat \
|
||||
figlet
|
||||
|
||||
RUN if [ "$BUILD_ARCH" != "armv7" ]; then apk add --no-cache apfs-fuse;fi
|
||||
|
||||
# WSDD2
|
||||
COPY --from=builder /wsdd2-master/wsdd2 /usr/sbin
|
||||
|
||||
# SAMBANAS UTILS (POERTY VIRTUAL ENV)
|
||||
COPY --from=builder /root/.cache/pypoetry /root/.cache/pypoetry
|
||||
|
||||
# HA API
|
||||
RUN curl -Lso /usr/bin/ha "https://github.com/home-assistant/cli/releases/download/${CLI_VERSION}/ha_${BUILD_ARCH}" \
|
||||
&& chmod a+x /usr/bin/ha
|
||||
|
||||
# SAMBA Config
|
||||
RUN mkdir -p /var/lib/samba \
|
||||
&& touch \
|
||||
/etc/samba/lmhosts \
|
||||
/var/lib/samba/account_policy.tdb \
|
||||
/var/lib/samba/registry.tdb \
|
||||
/var/lib/samba/winbindd_idmap.tdb
|
||||
|
||||
# ENABLE FUSE APFS
|
||||
RUN ln -s /usr/sbin/apfs-fuse /usr/sbin/mount.apfs
|
||||
|
||||
# Copy data
|
||||
COPY rootfs /
|
||||
|
||||
HEALTHCHECK \
|
||||
CMD smbclient -L '\\localhost' -U '%' -m SMB3
|
||||
|
||||
# Labels
|
||||
LABEL \
|
||||
io.hass.name="${BUILD_NAME}" \
|
||||
io.hass.description="${BUILD_DESCRIPTION}" \
|
||||
io.hass.arch="${BUILD_ARCH}" \
|
||||
io.hass.type="addon" \
|
||||
io.hass.version=${BUILD_VERSION} \
|
||||
maintainer="Lucio Tarantino <@dianlight>" \
|
||||
org.opencontainers.image.title="${BUILD_NAME}" \
|
||||
org.opencontainers.image.description="${BUILD_DESCRIPTION}" \
|
||||
org.opencontainers.image.vendor="Home Assistant Dianlight Add-ons" \
|
||||
org.opencontainers.image.authors="Lucio Tarantino <@dianlight>" \
|
||||
org.opencontainers.image.licenses="MIT" \
|
||||
org.opencontainers.image.url="https://github.com/dianlight/hassio-addons" \
|
||||
org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \
|
||||
org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \
|
||||
org.opencontainers.image.created=${BUILD_DATE} \
|
||||
org.opencontainers.image.revision=${BUILD_REF} \
|
||||
org.opencontainers.image.version=${BUILD_VERSION}
|
57
sambanas/README.md
Normal file
57
sambanas/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Home Assistant Add-on: Samba NAS share
|
||||
|
||||
Share your disks over the network using Windows file sharing.
|
||||
|
||||
![Supports aarch64 Architecture][aarch64-shield] ![Supports amd64 Architecture][amd64-shield] ![Supports armv7 Architecture][armv7-shield]
|
||||
|
||||
<!--
|
||||
[](https://github.com/dianlight/hassio-addons/stargazers)
|
||||
|
||||

|
||||
-->
|
||||
|
||||
## Important Notice Regarding SambaNas Addon Development
|
||||
|
||||
**SambaNas Addon is Now in Maintenance Mode**
|
||||
|
||||
This notice is to inform our users that the **SambaNas addon will now transition into maintenance mode.** This means that **no future features will be implemented** for this version of the addon. Our development efforts will be focused solely on providing **critical bug fixes** to ensure its continued stability for existing users.
|
||||
|
||||
**Introducing SambaNas2: The Future of Samba Integration**
|
||||
|
||||
We are excited to announce **SambaNas2**, the successor to the original SambaNas addon! SambaNas2 represents a **complete rewrite from the ground up, developed in Go with a brand new core.** This will bring significant improvements in performance, stability, and future extensibility.
|
||||
|
||||
**Current Status and Upcoming Beta Release**
|
||||
|
||||
SambaNas2 is currently in an **Alpha stage** of development. We are pleased to announce that a **public Beta version will be released in the coming weeks** and will be available through our beta channel.
|
||||
|
||||
We encourage users interested in the latest features and improvements to keep an eye out for the SambaNas2 beta release. Thank you for your continued support.
|
||||
|
||||
## Installations
|
||||
|
||||

|
||||

|
||||
|
||||
## Help Me!
|
||||
|
||||
[](https://github.com/sponsors/dianlight)
|
||||
|
||||
<a href="https://www.buymeacoffee.com/ypKZ2I0"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=ypKZ2I0&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff" /></a>
|
||||
|
||||
|
||||
## About
|
||||
|
||||
This Add-on allows you to enable file sharing across different operating systems over a network.
|
||||
It lets you access your config files with Windows and macOS devices.
|
||||
Also you can specify disk label to mount at boot and share.
|
||||
|
||||
|
||||
[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg
|
||||
[amd64-shield]: https://img.shields.io/badge/amd64-yes-green.svg
|
||||
[armhf-shield]: https://img.shields.io/badge/armhf-yes-green.svg
|
||||
[armv7-shield]: https://img.shields.io/badge/armv7-yes-green.svg
|
||||
[discord]: https://discord.gg/c5DvZ4e
|
||||
[forum]: https://community.home-assistant.io
|
||||
[i386-shield]: https://img.shields.io/badge/i386-yes-green.svg
|
||||
[issue]: https://github.com/dianlight/hassio-addons/issues
|
||||
[reddit]: https://reddit.com/r/homeassistant
|
||||
[repository]: https://github.com/dianlight/hassio-addons
|
67
sambanas/apparmor.txt
Normal file
67
sambanas/apparmor.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <tunables/global>
|
||||
|
||||
profile addon_samba_nas flags=(attach_disconnected,mediate_deleted) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/mdns>
|
||||
#include <abstractions/samba>
|
||||
#include <abstractions/smbpass>
|
||||
#include <abstractions/winbind>
|
||||
#include <abstractions/bash>
|
||||
|
||||
|
||||
capability,
|
||||
file,
|
||||
signal (send) set=(kill,term,int,hup,cont),
|
||||
mount,
|
||||
umount,
|
||||
remount,
|
||||
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
capability sys_admin,
|
||||
capability dac_read_search,
|
||||
capability sys_rawio,
|
||||
capability sys_resource,
|
||||
# capability dac_override,
|
||||
|
||||
# Networks
|
||||
network udp,
|
||||
network tcp,
|
||||
network dgram,
|
||||
network stream,
|
||||
network inet,
|
||||
network inet6,
|
||||
network netlink raw,
|
||||
network unix dgram,
|
||||
|
||||
# S6-Overlay
|
||||
/init ix,
|
||||
/bin/** ix,
|
||||
/usr/bin/** ix,
|
||||
/run/{s6,s6-rc*,service}/** ix,
|
||||
/package/** ix,
|
||||
/command/** ix,
|
||||
/etc/services.d/** rwix,
|
||||
/etc/cont-init.d/** rwix,
|
||||
/etc/cont-finish.d/** rwix,
|
||||
/run/{,**} rwk,
|
||||
# /dev/tty rw,
|
||||
|
||||
# Files required
|
||||
/dev/** mrwkl,
|
||||
/tmp/** mrkwl,
|
||||
|
||||
# Bashio
|
||||
/usr/lib/bashio/** ix,
|
||||
/tmp/** rwk,
|
||||
|
||||
# Data access
|
||||
/data/** rw,
|
||||
|
||||
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
|
||||
ptrace (trace,read) peer=docker-default,
|
||||
|
||||
# docker daemon confinement requires explict allow rule for signal
|
||||
signal (receive) set=(kill,term) peer=/usr/bin/docker,
|
||||
|
||||
}
|
13
sambanas/build.yaml
Normal file
13
sambanas/build.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
build_from:
|
||||
aarch64: ghcr.io/hassio-addons/base:17.2.5
|
||||
amd64: ghcr.io/hassio-addons/base:17.2.5
|
||||
armv7: ghcr.io/hassio-addons/base:17.2.5
|
||||
#codenotary:
|
||||
# signer: lucio.tarantino@gmail.com
|
||||
# base_image: codenotary@frenck.dev
|
||||
cosign:
|
||||
# #base_identity: https://github.com/home-assistant/builder/.*
|
||||
identity: https://github.com/dianlight/hassio-addons/.*
|
||||
#args:
|
||||
# HDDTEMP_VERSION: "0.3-beta15"
|
139
sambanas/config.yaml
Normal file
139
sambanas/config.yaml
Normal file
@@ -0,0 +1,139 @@
|
||||
---
|
||||
name: Samba NAS
|
||||
version: 12.5.0-nas
|
||||
slug: sambanas
|
||||
description: Expose Home Assistant disc with SMB/CIFS
|
||||
url: https://github.com/dianlight/hassio-addons/tree/master/sambanas
|
||||
codenotary: lucio.tarantino@gmail.com
|
||||
arch:
|
||||
- armv7
|
||||
- aarch64
|
||||
- amd64
|
||||
startup: initialize
|
||||
boot: auto
|
||||
init: false
|
||||
hassio_api: true
|
||||
hassio_role: admin
|
||||
host_network: true
|
||||
map:
|
||||
- homeassistant_config:rw
|
||||
- addon_config:rw
|
||||
- ssl:rw
|
||||
- all_addon_configs:rw
|
||||
- addons:rw
|
||||
- share:rw
|
||||
- backup:rw
|
||||
- media:rw
|
||||
options:
|
||||
workgroup: WORKGROUP
|
||||
username: homeassistant
|
||||
local_master: true
|
||||
allow_hosts:
|
||||
- 10.0.0.0/8
|
||||
- 172.16.0.0/12
|
||||
- 192.168.0.0/16
|
||||
- 169.254.0.0/16
|
||||
- fe80::/10
|
||||
- fc00::/7
|
||||
automount: true
|
||||
moredisks: []
|
||||
mountoptions:
|
||||
- nosuid
|
||||
- relatime
|
||||
- noexec
|
||||
available_disks_log: true
|
||||
medialibrary:
|
||||
enable: false
|
||||
veto_files:
|
||||
- "._*"
|
||||
- ".DS_Store"
|
||||
- Thumbs.db
|
||||
- icon?
|
||||
- ".Trashes"
|
||||
compatibility_mode: false
|
||||
recyle_bin_enabled: false
|
||||
wsdd2: false
|
||||
wsdd: true
|
||||
mqtt_nexgen_entities: false
|
||||
autodiscovery: {}
|
||||
other_users: []
|
||||
acl: []
|
||||
interfaces: []
|
||||
schema:
|
||||
workgroup: str
|
||||
local_master: bool
|
||||
username: str
|
||||
password: password
|
||||
automount: bool?
|
||||
moredisks:
|
||||
- str
|
||||
mountoptions:
|
||||
- str
|
||||
available_disks_log: bool?
|
||||
medialibrary:
|
||||
enable: bool?
|
||||
ssh_private_key: password?
|
||||
allow_hosts:
|
||||
- str
|
||||
veto_files:
|
||||
- str
|
||||
compatibility_mode: bool?
|
||||
recyle_bin_enabled: bool?
|
||||
wsdd: bool
|
||||
wsdd2: bool?
|
||||
hdd_idle_seconds: int(0,)?
|
||||
enable_smart: bool?
|
||||
mqtt_nexgen_entities: bool?
|
||||
mqtt_enable: bool?
|
||||
mqtt_host: str?
|
||||
mqtt_username: str?
|
||||
mqtt_password: password?
|
||||
mqtt_port: str?
|
||||
mqtt_topic: str?
|
||||
autodiscovery:
|
||||
disable_discovery: bool?
|
||||
disable_persistent: bool?
|
||||
disable_autoremove: bool?
|
||||
other_users:
|
||||
- username: str
|
||||
password: str
|
||||
acl:
|
||||
- share: str
|
||||
disabled: bool?
|
||||
users:
|
||||
- str?
|
||||
ro_users:
|
||||
- str?
|
||||
timemachine: bool?
|
||||
usage: list(media|backup|share)?
|
||||
interfaces:
|
||||
- str?
|
||||
bind_all_interfaces: bool?
|
||||
log_level: list(trace|debug|info|notice|warning|error|fatal)?
|
||||
meaning_of_life: int?
|
||||
multi_channel: bool?
|
||||
|
||||
image: dianlight/{arch}-addon-sambanas
|
||||
services:
|
||||
- mqtt:want
|
||||
udev: true
|
||||
#usb: true
|
||||
host_dbus: true
|
||||
kernel_modules: true
|
||||
privileged:
|
||||
- SYS_ADMIN
|
||||
- SYS_RAWIO
|
||||
- SYS_RESOURCE
|
||||
- SYS_MODULE
|
||||
full_access: true
|
||||
devicetree: false
|
||||
apparmor: true
|
||||
host_ipc: true
|
||||
advanced: true
|
||||
homeassistant: 2025.4.0
|
||||
backup: hot
|
||||
auth_api: true
|
||||
homeassistant_api: true
|
||||
timeout: 60
|
||||
breaking_versions:
|
||||
- 12.5.0-nas # Turn in maintence mode
|
BIN
sambanas/icon.png
Normal file
BIN
sambanas/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
sambanas/logo.png
Normal file
BIN
sambanas/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
11
sambanas/rootfs/etc/s6-overlay/s6-rc.d/avahi/finish
Normal file
11
sambanas/rootfs/etc/s6-overlay/s6-rc.d/avahi/finish
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree based on service exit code
|
||||
# ==============================================================================
|
||||
if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
|
||||
bashio::log.warning "avahi crashed, halting add-on"
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "avahi stopped"
|
12
sambanas/rootfs/etc/s6-overlay/s6-rc.d/avahi/run
Normal file
12
sambanas/rootfs/etc/s6-overlay/s6-rc.d/avahi/run
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Start avahi service
|
||||
# ==============================================================================
|
||||
declare SMB_HOST
|
||||
|
||||
SMB_HOST=$(grep -i '^\s*netbios name\s*=' /etc/samba/smb.conf | cut -f2 -d= | tr -d '[:blank:]')
|
||||
|
||||
bashio::log.info "Starting the AVAHI for ${SMB_HOST%.*}..."
|
||||
|
||||
exec avahi-publish-service -v -f -s "${SMB_HOST%.*}" _smb._tcp 445
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/avahi/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/avahi/type
Normal file
@@ -0,0 +1 @@
|
||||
longrun
|
@@ -0,0 +1 @@
|
||||
/etc/s6-overlay/s6-rc.d/cifs-supervisor-mount/finish
|
@@ -0,0 +1,17 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree based on service exit code
|
||||
# ==============================================================================
|
||||
|
||||
if [ -f /tmp/cifs_network ]; then
|
||||
bashio::log.info "Umount Network Automount Shares..."
|
||||
|
||||
available_shares=$(awk '/\[(.*)\]/{ DISK=substr($1,2,length($1)-2); next } /.*path =(.*)/{ printf "%s\n",DISK,$0 }' /etc/samba/smb.conf)
|
||||
|
||||
while read -r -a device; do
|
||||
[[ "share config addons ssl backup media all_addon_configs homeassistant" =~ ${device,,} ]] && continue
|
||||
status=$(bashio::api.supervisor DELETE /mounts/${device})
|
||||
bashio::log.info "Return from Umount ${status}"
|
||||
done <<<"${available_shares}"
|
||||
fi
|
@@ -0,0 +1,57 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Amoutomount Shares with new system!
|
||||
# ==============================================================================
|
||||
|
||||
if [ -f /tmp/cifs_network ]; then
|
||||
#bashio::log.level all
|
||||
|
||||
bashio::log.info "Automount Shares..."
|
||||
|
||||
ipaddress=$(bashio::addon.ip_address)
|
||||
|
||||
#username=$(bashio::config 'username')
|
||||
#password=$(bashio::config 'password')
|
||||
|
||||
username=$(jq -r '.username' </tmp/auth.json)
|
||||
password=$(jq -r '.password' </tmp/auth.json)
|
||||
|
||||
available_shares=$(awk '/\[(.*)\]/{ DISK=substr($1,2,length($1)-2); next } /.*path =(.*)/{ printf "%s\n",DISK,$0 }' /etc/samba/smb.conf)
|
||||
|
||||
#info=$(bashio::api.supervisor GET /host/info false)
|
||||
#bashio::log "Info: ${info}"
|
||||
|
||||
#mounts=$(bashio::api.supervisor GET /mounts false)
|
||||
#bashio::log "Mounts: ${mounts}"
|
||||
|
||||
#status=$(smbcontrol smbd ping)
|
||||
#bashio::log "Samba Ready: ${status}"
|
||||
#bashio::log "Children: $(smbcontrol smbd num-children)"
|
||||
|
||||
bashio::log.info "Wait Samba Server to going up..(max 60s)"
|
||||
# timeout 30 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' ${ipaddress/\/*/} 445
|
||||
bashio::net.wait_for 445 ${ipaddress/\/*/} 60
|
||||
# smbstatus
|
||||
|
||||
while read -r -a device; do
|
||||
[[ ${device,,} == @(share|config|addons|ssl|backup|media|addon_configs|homeassistant) ]] && continue
|
||||
usage=$(jq -r --arg xshare "$device" '.acl[] | select(.share==$xshare) | .usage // "media"' <<<"$(bashio::addon.config)")
|
||||
cmdshare=$(jq -nrc --arg usage "${usage:-media}" --arg share "$device" --arg ip "${ipaddress/\/*/}" --arg user "$username" --arg pwd "$password" '.name=$share|.usage=$usage|.type="cifs"|.server=$ip|.share=$share|.username=$user|.password=$pwd')
|
||||
#bashio::log.info $(jq '.password="********"' <<<${cmdshare})
|
||||
|
||||
#bashio::log.info $(bashio::api.supervisor GET /mounts)
|
||||
#bashio::log.info $(bashio::api.supervisor GET /mounts | jq -r --arg xshare "$device" '.mounts[] | select(.name == $xshare ) // empty')
|
||||
|
||||
if [[ ! -z $(bashio::api.supervisor GET /mounts | jq -r --arg xshare "$device" '.mounts[] | select(.name == $xshare ) // empty') ]]; then
|
||||
bashio::log.info "Share Already Found ${device} - Remove!"
|
||||
bashio::api.supervisor DELETE /mounts/${device} || true
|
||||
fi
|
||||
|
||||
for rt in {1..3}; do
|
||||
status=$(bashio::api.supervisor POST /mounts "${cmdshare}") && break
|
||||
bashio::log.warning "Retry ${rt}/3 Error Automount ${device} Msg: $(jq -c '.password="********"' <<<${cmdshare})"
|
||||
sleep 3
|
||||
done
|
||||
done <<<"${available_shares}"
|
||||
fi
|
@@ -0,0 +1 @@
|
||||
oneshot
|
@@ -0,0 +1 @@
|
||||
/etc/s6-overlay/s6-rc.d/cifs-supervisor-mount/run
|
10
sambanas/rootfs/etc/s6-overlay/s6-rc.d/hd-idle/finish
Normal file
10
sambanas/rootfs/etc/s6-overlay/s6-rc.d/hd-idle/finish
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree based on service exit code
|
||||
# ==============================================================================
|
||||
if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
|
||||
bashio::log.warning "hd-idle crashed, halting add-on"
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "hd-idle stopped"
|
13
sambanas/rootfs/etc/s6-overlay/s6-rc.d/hd-idle/run
Normal file
13
sambanas/rootfs/etc/s6-overlay/s6-rc.d/hd-idle/run
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Start hd-idle service
|
||||
# ==============================================================================
|
||||
if bashio::config.has_value 'hdd_idle_seconds' && ! bashio::config.equals 'hdd_idle_seconds' '0'; then
|
||||
bashio::log.info "Enabling HDD IDLE after $(bashio::config 'hdd_idle_seconds')sec"
|
||||
bashio::log.warning "HDD IDLE is subject to host file-handle policy. So severals minutes can be wait before real IDLE can be performed!"
|
||||
mkfifo /tmp/hdidle.events || true
|
||||
exec hd-idle -i "$(bashio::config 'hdd_idle_seconds')" | tee /tmp/hdidle.events
|
||||
else
|
||||
exec sleep infinity
|
||||
fi
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/hd-idle/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/hd-idle/type
Normal file
@@ -0,0 +1 @@
|
||||
longrun
|
@@ -0,0 +1 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-automount/finish
|
27
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-automount/finish
Normal file
27
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-automount/finish
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Umount all drivers.
|
||||
# ==============================================================================
|
||||
declare interface
|
||||
declare ipaddress
|
||||
|
||||
interface=$(bashio::network.name)
|
||||
ipaddress=$(bashio::network.ipv4_address ${interface})
|
||||
|
||||
if [[ -f /tmp/local_mount ]]; then
|
||||
readarray -t umdev </tmp/local_mount
|
||||
if [ ${#umdev[@]} -gt 0 ]; then
|
||||
bashio::log.info "Unmount drivers:\n$(printf "%s\n" "${umdev[@]}")"
|
||||
umount "${umdev[@]}" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
if [[ -f /tmp/remote_mount ]]; then
|
||||
readarray -t umdev </tmp/remote_mount
|
||||
if [ ${#umdev[@]} -gt 0 ]; then
|
||||
bashio::log.info "Unmount Host drivers:\n$(printf "%s\n" "${umdev[@]}")"
|
||||
line=$(printf "\"%s\" " "${umdev[@]}")
|
||||
ssh root@${ipaddress%/*} -p 22222 -o "StrictHostKeyChecking no" "umount $line" || true
|
||||
fi
|
||||
fi
|
||||
bashio::log.info "Bye."
|
313
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-automount/run
Normal file
313
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-automount/run
Normal file
@@ -0,0 +1,313 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Mounting external HD and modify the smb.conf
|
||||
# ==============================================================================
|
||||
declare moredisks
|
||||
declare autodisks
|
||||
declare tomountdisks
|
||||
declare interface
|
||||
declare ipaddress
|
||||
declare ssh_private_key
|
||||
declare remote_mount
|
||||
declare network_mount
|
||||
declare fstypes
|
||||
declare dev
|
||||
declare mntops
|
||||
declare reserved_names
|
||||
|
||||
function disk2label() { # $1 disk return (label disk or id)
|
||||
local disk=$1
|
||||
if [[ $disk == id:* ]]; then
|
||||
disk=${disk:3}
|
||||
if [ -L /dev/disk/by-id/"$disk" ]; then
|
||||
label=$(lsblk -no label /dev/disk/by-id/"$disk")
|
||||
# fstype=$(lsblk -no fstype /dev/disk/by-id/"$disk")
|
||||
if [[ -n "$label" && -L "/dev/disk/by-label/$label" ]]; then
|
||||
bashio::log.info "Disk with id ${disk} is labeled $label so $label is used."
|
||||
disk="$label"
|
||||
# elif [[ $fstype == apfs ]]; then
|
||||
# disk=$(apfsutil /dev/disk/by-id/"$disk" | awk -F "[, ]+" '/Name:/{print $2}')
|
||||
else
|
||||
disk=$1
|
||||
fi
|
||||
else
|
||||
bashio::log.warning "Disk with id ${disk} not found."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
blkid -L "$disk" >>/dev/null || {
|
||||
bashio::log.warning "Disk with label ${disk} not found."
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
echo "$disk"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check for reserved mount name
|
||||
function reserved_mount_name() { # $1 disk
|
||||
disk=$1
|
||||
reserved_names=(config addons ssl share backup media all_addon_configs homeassistant)
|
||||
|
||||
# Clean reserved name with disaled
|
||||
for rdisk in "${reserved_names[@]}"; do
|
||||
deleted=$(jq -r --arg share "${rdisk,,}" '.acl[] | select( (.share|ascii_upcase) == ($share|ascii_upcase) ) | select (.disabled) | .share' </data/options.json)
|
||||
reserved_names=("${reserved_names[@]/$deleted/}")
|
||||
done
|
||||
|
||||
# Clean tomountdisks
|
||||
for rdisk in "${reserved_names[@]}"; do
|
||||
if [[ ${rdisk,,} = ${disk,,} ]]; then
|
||||
tomountdisks=("${tomountdisks[@]/$disk/}")
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# mount a disk from parameters
|
||||
function mount_disk() { # $1 disk $2 path $3 remote_mount $4 mount_options
|
||||
disk=$1
|
||||
path=$2
|
||||
remote_mount=$3
|
||||
mntops=$4
|
||||
if [[ $disk == id:* ]]; then
|
||||
bashio::log.debug "Disk ${disk:3} is an ID"
|
||||
if [ -L "/dev/disk/by-uuid/${disk:3}" ]; then
|
||||
dev=/dev/disk/by-uuid/${disk:3}
|
||||
disk=${disk:3}
|
||||
elif [ -L "/dev/disk/by-id/${disk:3}" ]; then
|
||||
dev=/dev/disk/by-id/${disk:3}
|
||||
disk=${disk:3}
|
||||
elif [ -L "/dev/disk/by-partuuid/${disk:3}" ]; then
|
||||
dev=/dev/disk/by-partuuid/${disk:3}
|
||||
disk=${disk:3}
|
||||
else
|
||||
unset dev
|
||||
fi
|
||||
else
|
||||
dev=$(blkid -L "$disk")
|
||||
fi
|
||||
|
||||
if [ ! ${dev:+1} ]; then
|
||||
bashio::log.info "Disk ${disk} not found! <SKIP>"
|
||||
return 0
|
||||
fi
|
||||
|
||||
mdisk=$(printf %b "$disk")
|
||||
|
||||
mkdir -p "$path/$mdisk"
|
||||
chmod a+rwx "$path/$mdisk"
|
||||
|
||||
# check with findmnt if the disk is already mounted
|
||||
if findmnt -n -o TARGET "$path/$mdisk" >/dev/null 2>&1; then
|
||||
bashio::log.info "Disk ${mdisk} is already mounted"
|
||||
echo "$path"/"$mdisk" >>/tmp/local_mount
|
||||
return 0
|
||||
else
|
||||
# Check FS type and set relative options
|
||||
fstype=$(lsblk "$dev" -no fstype)
|
||||
options="${mntops}"
|
||||
type="auto"
|
||||
cmd="mount"
|
||||
case "$fstype" in
|
||||
exfat | vfat | msdos)
|
||||
bashio::log.warning "Your ${mdisk} is ${fstype}. Permissions and ACL don't works and this is an EXPERIMENTAL support"
|
||||
options="${options},umask=000"
|
||||
;;
|
||||
ntfs)
|
||||
bashio::log.warning "Your ${mdisk} is ${fstype}. This is an EXPERIMENTAL support"
|
||||
options="${options},umask=000"
|
||||
type="ntfs3"
|
||||
;;
|
||||
apfs)
|
||||
bashio::log.warning "Your ${mdisk} is ${fstype}. This is an EXPERIMENTAL support and work only in RO. Mount options not supported!"
|
||||
type=""
|
||||
options=""
|
||||
cmd="mount.apfs"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create mount arg array
|
||||
m_args=()
|
||||
if [ -n "$type" ]; then
|
||||
m_args+=("-t" $type)
|
||||
fi
|
||||
if [ -n "$options" ]; then
|
||||
m_args+=("-o" $options)
|
||||
fi
|
||||
m_args+=("${dev}")
|
||||
|
||||
bashio::log.debug "Mounting ${mdisk} of type ${fstype} with ${m_args[@]}"
|
||||
|
||||
if [ "$remote_mount" = true ]; then
|
||||
ssh root@"${ipaddress%/*}" -p 22222 -o "StrictHostKeyChecking no" "if findmnt '/mnt/data/supervisor/media/$mdisk ' >/dev/null; then echo 'Disk $mdisk already mounted on host' ; else $cmd ${m_args[@]} '/mnt/data/supervisor/media/$mdisk'; fi" &&
|
||||
echo "$dev" >>/tmp/remote_mount
|
||||
fi || bashio::log.warning "Host Mount ${mdisk}[${fstype}] Fail!" || :
|
||||
|
||||
bashio::log.debug "Exec command: ${cmd} ${m_args[@]} \"${path}/${mdisk}\""
|
||||
$cmd ${m_args[@]} "$path/$mdisk" &&
|
||||
echo "$path"/"$mdisk" >>/tmp/local_mount &&
|
||||
jq --arg dname "${mdisk}" --arg path "${path}/${mdisk}" --arg fs "${fstype}" ' . += {($dname | gsub( "-"; "_") | ascii_upcase ):{"path":$path,"fs":$fs}}' /tmp/local_mount.json >/tmp/local_mount.json.tmp &&
|
||||
mv /tmp/local_mount.json.tmp /tmp/local_mount.json &&
|
||||
bashio::log.info "Mount ${mdisk}[${fstype}] Success!"
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
# Error for Operating System
|
||||
if ! [[ "$(bashio::info.operating_system)" =~ ^Home\ Assistant\ OS.* ]]; then
|
||||
bashio::log.warning "Your operating system $(bashio::info.operating_system) is not supported! "
|
||||
bashio::log.red "+------------------------------------------------------------------+"
|
||||
bashio::log.red "| THIS ADDON IS DESIGNED FOR HOME ASSISTANT OPERATING SYSTEM ONLY! |"
|
||||
bashio::log.red "| THIS ADDON IS DESIGNED FOR HOME ASSISTANT OPERATING SYSTEM ONLY! |"
|
||||
bashio::log.red "| THIS ADDON IS DESIGNED FOR HOME ASSISTANT OPERATING SYSTEM ONLY! |"
|
||||
bashio::log.red "| THIS ADDON IS DESIGNED FOR HOME ASSISTANT OPERATING SYSTEM ONLY! |"
|
||||
bashio::log.red "| THIS ADDON IS DESIGNED FOR HOME ASSISTANT OPERATING SYSTEM ONLY! |"
|
||||
bashio::log.red "+------------------------------------------------------------------+"
|
||||
if bashio::config.exists 'meaning_of_life' && [[ $(bashio::config 'meaning_of_life') -eq 42 ]]; then
|
||||
bashio::log.green "Deep Thought permission accepted!"
|
||||
else
|
||||
bashio::exit.nok "You can force this addon to run only if you known the meaning of life!"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Mount external drive
|
||||
bashio::log.info "Protection Mode is $(bashio::addon.protected)"
|
||||
# shellcheck disable=SC2091
|
||||
if $(bashio::addon.protected) && (bashio::config.has_value 'moredisks' || bashio::config.true 'automount'); then
|
||||
bashio::log.warning "MoreDisk and Automount ignored because ADDON in Protected Mode!"
|
||||
bashio::config.suggest "protected" "moredisk only work when Protection mode is disabled"
|
||||
elif bashio::config.has_value 'moredisks' || bashio::config.true 'automount'; then
|
||||
bashio::log.info "MoreDisk or Automount option found!"
|
||||
|
||||
# Check supported FS
|
||||
for mfs in ntfs3 exfat btrfs xfs; do
|
||||
modprobe $mfs || bashio::log.warning "$mfs module not available!"
|
||||
done
|
||||
fstypes=$(grep -v nodev </proc/filesystems | tr -d '\n')
|
||||
bashio::log.blue "---------------------------------------------------"
|
||||
bashio::log.green "Supported fs: ${fstypes}"
|
||||
if grep -q fuseblk </proc/filesystems; then bashio::log.green "Supported fusefs: $(find /usr/sbin -name "mount*" | cut -c 17- | tr "\n" " " | sed s/fuse.//g)"; fi
|
||||
bashio::log.blue "---------------------------------------------------"
|
||||
|
||||
# Check Host Ssh config
|
||||
remote_mount=false
|
||||
network_mount=false
|
||||
path=/mnt
|
||||
|
||||
if bashio::config.true 'medialibrary.enable'; then
|
||||
bashio::log.info "MediaLibrary option found!"
|
||||
if bashio::config.is_empty 'medialibrary.ssh_private_key'; then
|
||||
# Check OS Capability
|
||||
features=$(bashio::info 'supervisor.info.features' '.features')
|
||||
#bashio::log "Features ${features}"
|
||||
if grep \"mount\" <<<"${features}" >/dev/null; then
|
||||
touch "/tmp/cifs_network"
|
||||
else
|
||||
bashio::log.warning "Unsupported Mount Feature by system!"
|
||||
bashio::config.suggest "ssh_private_key" "Your host system don't upport mount feature\nSSH Private Key is required for enable medialibrary deprected feature."
|
||||
fi
|
||||
else
|
||||
|
||||
bashio::log.red "+-------------------------------------------------------------------------------------+"
|
||||
bashio::log.warning "|SSH Private Key *DEPRECATED WARNING* The use of old experimental system is deprecated|"
|
||||
bashio::log.warning "|Remove the key and try the new system to mound /media and /share data disks |"
|
||||
bashio::log.red "+-------------------------------------------------------------------------------------+"
|
||||
|
||||
interface=$(bashio::network.name)
|
||||
ipaddress=$(bashio::network.ipv4_address "${interface}")
|
||||
ssh_private_key=$(bashio::config 'medialibrary.ssh_private_key')
|
||||
mkdir -p /root/.ssh
|
||||
echo "${ssh_private_key}" >/root/.ssh/id_rsa
|
||||
chmod ag-rw /root/.ssh/id_rsa
|
||||
|
||||
if ssh root@"${ipaddress%/*}" -p 22222 -o "StrictHostKeyChecking no" "date"; then
|
||||
bashio::log.info "SSH connection to ${ipaddress%/*}:22222 OK"
|
||||
remote_mount=true
|
||||
path=/media
|
||||
else
|
||||
bashio::log.warning "SSH connection to ${ipaddress%/*}:22222 FAILED"
|
||||
bashio::log.warning "MediaLibrary disabled due error in config!"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
bashio::log.info "MediaLibrary disabled in config. Disk are mounted only for this addon!"
|
||||
fi
|
||||
|
||||
OIFS=$IFS
|
||||
IFS=$'\n'
|
||||
|
||||
## List available Disk with Labels and Id
|
||||
if bashio::config.true 'available_disks_log' || bashio::config.true 'automount'; then
|
||||
bashio::log.blue "---------------------------------------------------"
|
||||
#readarray -t autodisks < <(lsblk -E label -n -o label -i | sed -r '/^\s*$/d' | grep -v hassos)
|
||||
readarray -t autodisks < <(/usr/bin/poetry -C /usr/local/bin/ run python /usr/local/bin/disklist.py)
|
||||
|
||||
if [ ${#autodisks[@]} -eq 0 ]; then
|
||||
bashio::log.info "No Disk with labels."
|
||||
else
|
||||
bashio::log.info "Available Disk Labels:"
|
||||
for disk in "${autodisks[@]}"; do
|
||||
if [[ $disk == id:* ]]; then
|
||||
bashio::log.info "\t${disk}[$(lsblk $(blkid -U "${disk:3}") -no fstype)]"
|
||||
else
|
||||
bashio::log.info "\t${disk}[$(lsblk $(blkid -L "$disk") -no fstype)]"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
bashio::log.blue "---------------------------------------------------"
|
||||
fi
|
||||
|
||||
mnt_ops=($(bashio::config 'mountoptions'))
|
||||
mnt_ops=$(
|
||||
IFS=,
|
||||
echo "${mnt_ops[*]}"
|
||||
)
|
||||
|
||||
moredisks=($(bashio::config 'moredisks'))
|
||||
if [ ${#moredisks[@]} -eq 0 ]; then
|
||||
bashio::log.info "No MoreDisks to mount"
|
||||
else
|
||||
bashio::log.info "MoreDisks to mount:\n" $(printf "\t%s\n" "${moredisks[@]}")
|
||||
i=0
|
||||
mmoredisks=()
|
||||
for index in "${!moredisks[@]}"; do
|
||||
tmpd=$(disk2label "${moredisks[$index]}") &&
|
||||
mmoredisks[$i]=$tmpd &&
|
||||
((i = i + 1))
|
||||
done
|
||||
moredisks=("${mmoredisks[@]}")
|
||||
fi
|
||||
|
||||
if bashio::config.true 'automount' && [ ${#autodisks[@]} -gt 0 ]; then
|
||||
bashio::log.info "Automount is Enabled!"
|
||||
tomountdisks=("${autodisks[@]}" "${moredisks[@]}")
|
||||
tomountdisks=($(sort -u <<<"${tomountdisks[*]}"))
|
||||
else
|
||||
tomountdisks=("${moredisks[@]}")
|
||||
fi
|
||||
|
||||
if [ ${#tomountdisks[@]} -gt 0 ]; then
|
||||
bashio::log.magenta "---------------------------------------------------"
|
||||
bashio::log.info "Checking Mounting disks for reserved names:\n" $(printf "\t%s\n" "${tomountdisks[@]}")
|
||||
bashio::log.magenta "---------------------------------------------------"
|
||||
for disk in "${tomountdisks[@]}"; do
|
||||
reserved_mount_name "$disk" || bashio::log.warning "Fail to mount ${disk} due to reserved name!"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "{}" >/tmp/local_mount.json
|
||||
|
||||
if [ ${#tomountdisks[@]} -gt 0 ]; then
|
||||
bashio::log.magenta "---------------------------------------------------"
|
||||
bashio::log.info "Mounting disks:\n" $(printf "\t%s\n" "${tomountdisks[@]}")
|
||||
bashio::log.magenta "---------------------------------------------------"
|
||||
for disk in "${tomountdisks[@]}"; do
|
||||
mount_disk "$disk" "$path" "$remote_mount" "$mnt_ops" || bashio::log.warning "Fail to mount ${disk} ${mnt_ops} !"
|
||||
done
|
||||
fi
|
||||
IFS=$OIFS
|
||||
|
||||
echo "$path" >/tmp/mountpath
|
||||
fi
|
@@ -0,0 +1 @@
|
||||
oneshot
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-automount/up
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-automount/up
Normal file
@@ -0,0 +1 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-automount/run
|
47
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-mqtt/run
Normal file
47
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-mqtt/run
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Prepare the MQTT config for running
|
||||
# ==============================================================================
|
||||
readonly CONF="/root/.config/mosquitto_pub"
|
||||
readonly CONF_SUB="/root/.config/mosquitto_sub"
|
||||
declare host
|
||||
declare username
|
||||
declare password
|
||||
declare port
|
||||
declare topic
|
||||
|
||||
if bashio::config.true "mqtt_enable"; then
|
||||
|
||||
|
||||
topic=$(bashio::config 'mqtt_topic' "sambanas")
|
||||
host=$(bashio::config 'mqtt_host' "$(bashio::services 'mqtt' 'host')")
|
||||
username=$(bashio::config 'mqtt_username' "$(bashio::services 'mqtt' 'username')")
|
||||
password=$(bashio::config 'mqtt_password' "$(bashio::services 'mqtt' 'password')")
|
||||
port=$(bashio::config 'mqtt_port' "$(bashio::services 'mqtt' 'port')")
|
||||
|
||||
topic=$(bashio::config 'mqtt_topic')
|
||||
|
||||
#bashio::log.info "Init MQTT config ${host}:${port} ${username}:${password}"
|
||||
|
||||
[ -z "$host" ] && bashio::log.warning "No MQTT Server found. Homeassistant integration can't work!"
|
||||
|
||||
if bashio::var.has_value "host" && ! bashio::config.false "mqtt_enable" && [ -n "$host" ]; then
|
||||
{
|
||||
echo "-h ${host}"
|
||||
echo "--username ${username}"
|
||||
echo "--pw ${password}"
|
||||
echo "--port ${port}"
|
||||
} >"${CONF}"
|
||||
{
|
||||
echo "-h ${host}"
|
||||
echo "--username ${username}"
|
||||
echo "--pw ${password}"
|
||||
echo "--port ${port}"
|
||||
} >"${CONF_SUB}"
|
||||
fi
|
||||
else
|
||||
|
||||
bashio::log.info "MQTT support not enabled in config"
|
||||
|
||||
fi
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-mqtt/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-mqtt/type
Normal file
@@ -0,0 +1 @@
|
||||
oneshot
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-mqtt/up
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-mqtt/up
Normal file
@@ -0,0 +1 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-mqtt/run
|
99
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-samba/run
Normal file
99
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-samba/run
Normal file
@@ -0,0 +1,99 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# vim: ft=bash
|
||||
# ==============================================================================
|
||||
# Prepare the Samba service for running
|
||||
# ==============================================================================
|
||||
declare password
|
||||
declare username
|
||||
declare -a interfaces=()
|
||||
export HOSTNAME
|
||||
|
||||
# Check Login data
|
||||
bashio::config.require 'username'
|
||||
bashio::config.require 'password'
|
||||
|
||||
# Read hostname from API or setting default "hassio"
|
||||
HOSTNAME=$(bashio::info.hostname)
|
||||
if bashio::var.is_empty "${HOSTNAME}" || [ "${HOSTNAME}" == "null" ]; then
|
||||
bashio::log.warning "Can't read hostname, using default."
|
||||
HOSTNAME="homeassistant"
|
||||
fi
|
||||
bashio::log.info "Hostname: ${HOSTNAME}"
|
||||
|
||||
if bashio::config.has_value 'interfaces'; then
|
||||
bashio::log.debug "Interfaces from config: $(bashio::config 'interfaces')"
|
||||
for interface in $(bashio::config 'interfaces'); do
|
||||
if [ -d "/sys/class/net/${interface}" ]; then
|
||||
interfaces+=("${interface}")
|
||||
else
|
||||
bashio::log.warning "Interface ${interface} not found, skipping."
|
||||
fi
|
||||
done
|
||||
else
|
||||
# Get supported interfaces
|
||||
for interface in $(bashio::network.interfaces); do
|
||||
interfaces+=("${interface}")
|
||||
done
|
||||
fi
|
||||
|
||||
if [ ${#interfaces[@]} -eq 0 ]; then
|
||||
bashio::exit.nok 'No supported interfaces found to bind on.'
|
||||
fi
|
||||
bashio::log.info "Interfaces: $(printf '%s ' "${interfaces[@]}")"
|
||||
bashio::log.info "Docker Interface: $(bashio::network 'network.info.docker.inerface' '.docker.interface') $(bashio::network 'network.info.docker.network' '.docker.address')"
|
||||
|
||||
# Generate Samba configuration.
|
||||
touch /tmp/local_mount
|
||||
if [[ ! -e /tmp/local_mount.json ]]; then
|
||||
echo "{}" >/tmp/local_mount.json
|
||||
fi
|
||||
|
||||
jq ".shares = $(jq -c </tmp/local_mount.json) | .interfaces = $(jq -c -n '$ARGS.positional' --args -- "${interfaces[@]}") | .docker_interface = \"$(bashio::network 'network.info.docker.inerface' '.docker.interface')\" | .docker_net = \"$(bashio::network 'network.info.docker.network' '.docker.address')\" | .moredisks = $(jq -R -s -c 'split("\n") | map(select(length > 0)) | [ .[] | ltrimstr("/") ]' </tmp/local_mount) " /data/options.json |
|
||||
tee /config/bootconfig.json |
|
||||
tempio \
|
||||
-template /usr/share/tempio/smb.gtpl \
|
||||
-out /etc/samba/smb.conf
|
||||
|
||||
if [[ "${__BASHIO_LOG_LEVEL_TRACE}" -eq "${__BASHIO_LOG_LEVEL}" ]]; then
|
||||
bashio::log.info "${__BASHIO_LOG_LEVEL_TRACE} ${__BASHIO_LOG_LEVEL}"
|
||||
bashio::log.trace "Dump SMB.conf to ADDON_CONFIG/$(hostname) share"
|
||||
cp /etc/samba/smb.conf /config/smb.conf.dump
|
||||
fi
|
||||
|
||||
function addSambaUser() { # $1 username $2 password
|
||||
username=$1
|
||||
password=$2
|
||||
addgroup "${username}"
|
||||
adduser -D -H -G "${username}" -s /bin/false "${username}"
|
||||
(
|
||||
echo "$password"
|
||||
echo "$password"
|
||||
) |
|
||||
smbpasswd -a -s -c "/etc/samba/smb.conf" "${username}"
|
||||
}
|
||||
|
||||
# Init user
|
||||
username=$(bashio::config 'username')
|
||||
password=$(bashio::config 'password')
|
||||
addSambaUser "${username}" "${password}"
|
||||
|
||||
# Init superuser
|
||||
if [ -f /tmp/cifs_network ]; then
|
||||
username="_ha_mount_user_"
|
||||
password=$(sed 's/[-]//g' /proc/sys/kernel/random/uuid | head -c 20)
|
||||
addSambaUser "${username}" "${password}"
|
||||
jq -n --arg username "${username}" --arg password "${password}" '{username:$username, password:$password}' >/tmp/auth.json
|
||||
fi
|
||||
|
||||
# Create other users
|
||||
for user in $(bashio::config 'other_users'); do
|
||||
username=$(echo "${user}" | jq -r '.username')
|
||||
password=$(echo "${user}" | jq -r '.password')
|
||||
addSambaUser "${username}" "${password}"
|
||||
done
|
||||
|
||||
# Log exposed mounted shares
|
||||
bashio::log.blue "---------------------------------------------------"
|
||||
bashio::log.info "Exposed Disks Summary:\n$(awk '/\[.*\]$/{ DISK=$0; next } /.*path =(.*)/{ PATH=$0; next} /.*TM:(.*)/{ printf "%-20s %s %s#\n",DISK,PATH,$0 }' /etc/samba/smb.conf)"
|
||||
bashio::log.blue "---------------------------------------------------"
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-samba/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-samba/type
Normal file
@@ -0,0 +1 @@
|
||||
oneshot
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-samba/up
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-samba/up
Normal file
@@ -0,0 +1 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-samba/run
|
14
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-smartd/run
Normal file
14
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-smartd/run
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Prepare the SMART config for disks
|
||||
# ==============================================================================
|
||||
|
||||
if ! bashio::config.false "enable_smart"; then
|
||||
smartctl --scan-open | while read -r -a device; do
|
||||
bashio::log.info "Enabling S.M.A.R.T for ${device[0]}"
|
||||
smartctl --smart=on --offlineauto=on --saveauto=on --quietmode=errorsonly "${device[0]}" || true
|
||||
done
|
||||
else
|
||||
bashio::log.info "SMART support disabled in config"
|
||||
fi
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-smartd/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-smartd/type
Normal file
@@ -0,0 +1 @@
|
||||
oneshot
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-smartd/up
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-smartd/up
Normal file
@@ -0,0 +1 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-smartd/run
|
@@ -0,0 +1,24 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree based on service exit code
|
||||
# ==============================================================================
|
||||
declare topic
|
||||
|
||||
if bashio::config.false "mqtt_nexgen_entities"; then
|
||||
if ! bashio::config.true "autodiscovery.disable_autoremove"; then
|
||||
bashio::log.info "MQTT disk cleanup."
|
||||
topic=$(bashio::config 'mqtt_topic')
|
||||
if [ "$topic" = "null" ]; then topic="sambanas"; fi
|
||||
mosquitto_sub -t "homeassistant/+/${topic}/+/config" --remove-retained -W 3 >/dev/null || true
|
||||
mosquitto_sub -t "${topic}/state" --remove-retained -W 3 >/dev/null || true
|
||||
bashio::log.info "MQTT disk cleanup Done."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
|
||||
bashio::log.warning "mqtt-handler crashed, halting add-on"
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "mqtt-handler stopped"
|
171
sambanas/rootfs/etc/s6-overlay/s6-rc.d/mqtt-disk-handler/run
Normal file
171
sambanas/rootfs/etc/s6-overlay/s6-rc.d/mqtt-disk-handler/run
Normal file
@@ -0,0 +1,171 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Start mqtt service for disk only
|
||||
# ==============================================================================
|
||||
|
||||
readonly MAX_TIMEFRAME=60
|
||||
readonly MIN_TIMEFRAME=10
|
||||
readonly AVG_TIMEFRAME=$(((MAX_TIMEFRAME + MIN_TIMEFRAME) / 2))
|
||||
|
||||
if bashio::config.true "mqtt_nexgen_entities"; then
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if [ -f /root/.config/mosquitto_pub ]; then
|
||||
bashio::log.info "Starting the MQTT daemon for disks info..."
|
||||
|
||||
# Send autodiscovery entities
|
||||
topic=$(bashio::config 'mqtt_topic')
|
||||
if [ "$topic" = "null" ]; then topic="sambanas"; fi
|
||||
|
||||
# Send discovery messages.
|
||||
if ! bashio::config.true "autodiscovery.disable_persistent"; then prs="-r"; fi
|
||||
|
||||
jdevice=$(jq -r -c -n --arg topic "$topic" --arg smbv "$(smbd -V | sed s/Version\ //)" --arg addon "$(bashio::addon.version)" '
|
||||
{device:{
|
||||
identifiers:[],
|
||||
name: "SambaNas Physical Disk ",
|
||||
hw_version: $addon,
|
||||
sw_version: $smbv,
|
||||
model: "SambaNas",
|
||||
manufacturer: "@Dianlight",
|
||||
via_device: $topic
|
||||
}}')
|
||||
|
||||
device_scan=$(smartctl --scan-open)
|
||||
|
||||
if [ -z "$device_scan" ]; then
|
||||
bashio::log.warning "No disk with S.M.A.R.T support found. Disable sensor report"
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
while read -r -a device; do
|
||||
|
||||
row=$(smartctl -A -l error -l selftest "${device[0]}" -j | jq '. * (.ata_smart_attributes.table // [] | INDEX(.name)) | del(.ata_smart_attributes.table)')
|
||||
#bashio::log.info "2.2 ${row}"
|
||||
for entity in device.name device.type device.protocol power_on_time.hours power_cycle_count temperature.current \
|
||||
Raw_Read_Error_Rate.raw.value Reallocated_Sector_Ct.raw.value Wear_Leveling_Count.raw.value UDMA_CRC_Error_Count.raw.value \
|
||||
ata_smart_error_log.summary.count ata_smart_self_test_log.standard.count; do
|
||||
|
||||
if [[ -z $(jq ".$entity // empty" <<<"$row") ]]; then
|
||||
# bashio::log.info "2.2 Missing ${entity} in ${row}"
|
||||
continue
|
||||
fi
|
||||
|
||||
exmsg={}
|
||||
etype=""
|
||||
|
||||
base=$(jq --arg topic "$topic" --arg entity "$entity" '
|
||||
{
|
||||
name:($topic+" "+$entity +" "+.device.info_name),
|
||||
unique_id:((.device.name | explode | join("")) + "-" + ($entity|explode|join(""))),
|
||||
value_template:("{{ value_json." +$entity+ "}}"),
|
||||
state_topic:($topic + "/" + (.device.name | gsub("[^A-z]";"")) + "/state" ),
|
||||
oth:{
|
||||
uuid:.device.name | explode | join(""),
|
||||
label:.device.name
|
||||
}
|
||||
}' <<<"$row")
|
||||
|
||||
case "$entity" in
|
||||
device.name | device.type | device.protocol) #TEXT
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" '
|
||||
{
|
||||
mode: "text",
|
||||
icon:"mdi:harddisk"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
power_on_time.hours) #Time
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" '
|
||||
{
|
||||
unit_of_measurement: "h",
|
||||
device_class: "duration"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
power_cycle_count) #number
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" '
|
||||
{
|
||||
_unit_of_measurement: "",
|
||||
icon:"mdi:power-cycle"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
Raw_Read_Error_Rate.raw.value | Reallocated_Sector_Ct.raw.value | Wear_Leveling_Count.raw.value | UDMA_CRC_Error_Count.raw.value | ata_smart_error_log.summary.count | ata_smart_self_test_log.standard.count) #number
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" '
|
||||
{
|
||||
_unit_of_measurement: "",
|
||||
icon:"mdi:chart-box-outline"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
temperature.current) #temperature
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" '
|
||||
{
|
||||
unit_of_measurement: "°C",
|
||||
device_class: "temperature",
|
||||
_icon:"mdi:thermometer"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
*)
|
||||
bashio::log.warning "Autodiscovery for $entity missing!"
|
||||
;;
|
||||
esac
|
||||
#bashio::log.info "2.4 $base $exmsg"
|
||||
msg=$(echo "$base" "$jdevice" "$exmsg" | jq -s 'add|.device.identifiers[.device.identifiers|length]=.oth.uuid|.device.name=(.device.name + .oth.label)|del(.oth)')
|
||||
#bashio::log.debug "$msg"
|
||||
mosquitto_pub "${prs}" -t "homeassistant/${etype}/${topic}/$(jq -r '.device.name | explode | join("")' <<<$row)-${entity//[\.\/]/-}/config" -m "$msg"
|
||||
done
|
||||
|
||||
# bashio::log.info "2.3"
|
||||
|
||||
done <<<"${device_scan}"
|
||||
|
||||
while read -r -a device; do
|
||||
mkfifo /tmp/mqtt-hanlder-${device[0]//\//}
|
||||
# Send status message process
|
||||
tail -F /tmp/mqtt-hanlder-${device[0]//\//} | mosquitto_pub -l -t "${topic}/${device[0]//\//}/state" &
|
||||
done <<<"${device_scan}"
|
||||
|
||||
while read -r -a device; do
|
||||
cdevice=${device[0]//\//}
|
||||
shaOldMessage="-"
|
||||
sleepTime=$AVG_TIMEFRAME
|
||||
while true; do
|
||||
#bashio::log.info "[$cdevice] ${shaOldMessage} $sleepTime"
|
||||
status=$(smartctl -A -l error -l selftest "${device[0]}" -j | jq -c '. * (.ata_smart_attributes.table // [] | INDEX(.name)) | del(.ata_smart_attributes.table) | del(.local_time) | del(.smartctl) | del (.json_format_version)')
|
||||
# Debug
|
||||
shaMessage=$(sha1sum <<<"$status")
|
||||
# bashio::log.green "[$cdevice] SleepTimes: $sleepTime $shaOldMessage] ${status}"
|
||||
if [ "${shaOldMessage}" = "$shaMessage" ]; then
|
||||
sleepTime=$((sleepTime * 2))
|
||||
[ ${sleepTime} -gt $MAX_TIMEFRAME ] && sleepTime=$MAX_TIMEFRAME
|
||||
else
|
||||
# Send status message
|
||||
if [ $sleepTime -gt $AVG_TIMEFRAME ]; then
|
||||
sleepTime=$((sleepTime / 2))
|
||||
else
|
||||
sleepTime=$((sleepTime - MIN_TIMEFRAME))
|
||||
fi
|
||||
[ $sleepTime -le $MIN_TIMEFRAME ] && sleepTime=$MIN_TIMEFRAME
|
||||
fi
|
||||
jq -c --arg st "$sleepTime" --arg sh "$shaMessage" '. +
|
||||
{
|
||||
ref: {
|
||||
mws: $st,
|
||||
sha: $sh
|
||||
}
|
||||
}' <<<"${status}" >/tmp/mqtt-hanlder-$cdevice
|
||||
shaOldMessage=$shaMessage
|
||||
# Sleep
|
||||
sleep ${sleepTime}
|
||||
done &
|
||||
sleep $((10 / $(wc -l <<<"$device_scan")))
|
||||
done <<<"${device_scan}"
|
||||
wait
|
||||
else
|
||||
exec sleep infinity
|
||||
fi
|
@@ -0,0 +1 @@
|
||||
longrun
|
24
sambanas/rootfs/etc/s6-overlay/s6-rc.d/mqtt-handler/finish
Normal file
24
sambanas/rootfs/etc/s6-overlay/s6-rc.d/mqtt-handler/finish
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree based on service exit code
|
||||
# ==============================================================================
|
||||
declare topic
|
||||
|
||||
if bashio::config.false "mqtt_nexgen_entities"; then
|
||||
if ! bashio::config.true "autodiscovery.disable_autoremove"; then
|
||||
bashio::log.info "MQTT cleanup."
|
||||
topic=$(bashio::config 'mqtt_topic')
|
||||
if [ "$topic" = "null" ]; then topic="sambanas"; fi
|
||||
mosquitto_sub -t "homeassistant/+/${topic}/+/config" --remove-retained -W 3 >/dev/null || true
|
||||
mosquitto_sub -t "${topic}/state" --remove-retained -W 3 >/dev/null || true
|
||||
bashio::log.info "MQTT cleanup Done."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
|
||||
bashio::log.warning "mqtt-handler crashed, halting add-on"
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "mqtt-handler stopped"
|
177
sambanas/rootfs/etc/s6-overlay/s6-rc.d/mqtt-handler/run
Normal file
177
sambanas/rootfs/etc/s6-overlay/s6-rc.d/mqtt-handler/run
Normal file
@@ -0,0 +1,177 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Start mqtt service
|
||||
# ==============================================================================
|
||||
|
||||
readonly MAX_TIMEFRAME=60
|
||||
readonly MIN_TIMEFRAME=5
|
||||
readonly AVG_TIMEFRAME=$(((MAX_TIMEFRAME + MIN_TIMEFRAME) / 2))
|
||||
|
||||
if [ -f /root/.config/mosquitto_pub ]; then
|
||||
bashio::log.info "Starting the MQTT daemon for partitions info..."
|
||||
|
||||
topic=$(bashio::config 'mqtt_topic' "sambanas")
|
||||
|
||||
# Send autodiscovery entities
|
||||
if bashio::config.true "mqtt_nexgen_entities"; then
|
||||
bashio::log.info "New MQTT integration"
|
||||
|
||||
host=$(bashio::config 'mqtt_host' "$(bashio::services 'mqtt' 'host')")
|
||||
username=$(bashio::config 'mqtt_username' "$(bashio::services 'mqtt' 'username')")
|
||||
password=$(bashio::config 'mqtt_password' "$(bashio::services 'mqtt' 'password')")
|
||||
port=$(bashio::config 'mqtt_port' "$(bashio::services 'mqtt' 'port')")
|
||||
log_level=$(bashio::string.lower "$(bashio::config log_level info)")
|
||||
|
||||
#bashio::log.info "New MQTT config ${host}:${port:-1883} ${username}:${password} ${topic}"
|
||||
|
||||
idleparam=""
|
||||
if [ -p /tmp/hdidle.events ]; then
|
||||
idleparam="-i /tmp/hdidle.events"
|
||||
fi
|
||||
|
||||
exec /usr/bin/poetry -C /usr/local/bin/ run python /usr/local/bin/mqtt_daemon.py -b "${host}" -p "${port:-1883}" -u "${username}" -P "${password}" -t "${topic}" -v $(bashio::addon.version) ${idleparam} -l ${log_level^^}
|
||||
else
|
||||
bashio::log.info "MQTT integration"
|
||||
|
||||
# disks=$(awk 'BEGIN { ORS=""; print "["} /^ path = .*/g { printf "%s\"%s\"",separator,$3 ; separator="," } END { print "]" } ' /etc/samba/smb.conf)
|
||||
disks=$(grep path /etc/samba/smb.conf | sed 's/.*path\ =\ //' | jq --raw-input --slurp 'split("\n") | map(select(. != ""))')
|
||||
blk=$(lsblk -b -no PARTUUID,NAME,LABEL,FSTYPE,MOUNTPOINTS -J -y)
|
||||
jdisks=$(jq --argjson disks "$disks" 'reduce (.blockdevices[].children[]? |select(.mountpoints? - $disks != .mountpoints) ) as $i ({};.[$i.name] = $i)' <<<${blk})
|
||||
|
||||
# Send discovery messages.
|
||||
if ! bashio::config.true "autodiscovery.disable_persistent"; then prs="-r"; fi
|
||||
|
||||
#bashio::log.info $device
|
||||
device=$(jq -r -c -n --arg topic "$topic" --arg smbv "$(smbd -V | sed s/Version\ //)" --arg addon "$(bashio::addon.version)" '
|
||||
{device:{
|
||||
identifiers:[],
|
||||
name: "SambaNas Disk ",
|
||||
hw_version: $addon,
|
||||
sw_version: $smbv,
|
||||
model: "SambaNas",
|
||||
manufacturer: "@Dianlight",
|
||||
via_device: $topic
|
||||
}}')
|
||||
|
||||
for row in $(jq -r '.|map(.|@base64)|.[]' <<<"$jdisks"); do
|
||||
for entity in name label mountpoints fssize fsused fsuse_pct fsavail fstype iostat.tps iostat.kB_read/s iostat.kB_wrtn/s iostat.kB_dscd/s iostat.kB_read iostat.kB_wrtn iostat.kB_dscd; do
|
||||
exmsg={}
|
||||
etype=""
|
||||
|
||||
base=$(jq --arg topic "$topic" --arg entity "$entity" -R '@base64d|fromjson|
|
||||
{
|
||||
name:($topic+" "+$entity +" "+ .label),
|
||||
unique_id:(.partuuid +"-"+ ($entity|explode|join(""))),
|
||||
value_template:("{{ value_json." + .name + "." +$entity+ "}}"),
|
||||
state_topic:($topic + "/state"),
|
||||
oth:{
|
||||
partuuid:.partuuid,
|
||||
name:.name,
|
||||
label:.label,
|
||||
root:("/dev/" + .name[:-1])
|
||||
}
|
||||
}' <<<"$row")
|
||||
|
||||
case "$entity" in
|
||||
name | label | fstype | mountpoints) #TEXT
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" -R '@base64d|fromjson|
|
||||
{
|
||||
mode: "text",
|
||||
icon:"mdi:harddisk"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
fssize | fsused | fsavail) #DATA_SIZE (Byte)
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" -R '@base64d|fromjson|
|
||||
{
|
||||
unit_of_measurement: "B",
|
||||
device_class: "data_size",
|
||||
}' <<<"$row")
|
||||
;;
|
||||
iostat.kB_read | iostat.kB_wrtn | iostat.kB_dscd) #DATA_SIZE (KB)
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" -R '@base64d|fromjson|
|
||||
{
|
||||
unit_of_measurement: "kB",
|
||||
device_class: "data_size",
|
||||
}' <<<"$row")
|
||||
;;
|
||||
iostat.kB_read/s | iostat.kB_wrtn/s | iostat.kB_dscd/s) #data_rate
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entityb "${entity%.*}" --arg entityd "${entity##*.}" -R '@base64d|fromjson|
|
||||
{
|
||||
unit_of_measurement: "kB/s",
|
||||
device_class: "data_rate",
|
||||
value_template:("{{ value_json." + .name + "." +$entityb+ "['"'"'" + $entityd + "'"'"']}}"),
|
||||
icon:"mdi:database-refresh"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
iostat.tps) #TPS
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" -R '@base64d|fromjson|
|
||||
{
|
||||
unit_of_measurement: "tps",
|
||||
icon:"mdi:database-search"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
fsuse_pct) # PERCENT
|
||||
etype="sensor"
|
||||
exmsg=$(jq --arg topic "$topic" --arg entity "$entity" -R '@base64d|fromjson|
|
||||
{
|
||||
unit_of_measurement: "%",
|
||||
icon:"mdi:database-eye"
|
||||
}' <<<"$row")
|
||||
;;
|
||||
*)
|
||||
bashio::log.warning "Autodiscovery for $entity missing!"
|
||||
;;
|
||||
esac
|
||||
msg=$(echo "$base" "$device" "$exmsg" | jq -s 'add|.device.identifiers[.device.identifiers|length]=.oth.partuuid|.device.name=(.device.name + .oth.label)|.device.via_device=(.oth.root | explode | join(""))|del(.oth)')
|
||||
#bashio::log.debug "$msg"
|
||||
mosquitto_pub "${prs}" -t "homeassistant/${etype}/${topic}/$(jq -R -r '@base64d|fromjson|.partuuid' <<<"$row")-${entity//[\.\/]/-}/config" -m "$msg"
|
||||
done
|
||||
done
|
||||
|
||||
mkfifo /tmp/mqtt-hanlder
|
||||
# Send status message process
|
||||
tail -F /tmp/mqtt-hanlder | mosquitto_pub -l -t "${topic}/state" &
|
||||
|
||||
sleepTime=$AVG_TIMEFRAME
|
||||
shaOldMessage="-"
|
||||
|
||||
while true; do
|
||||
blk=$(lsblk -b -no NAME,LABEL,FSSIZE,FSUSED,FSUSE%,FSAVAIL,FSTYPE,MOUNTPOINTS -J -y | jq 'walk(if type == "object" and .fsuse_pct != null then .fsuse_pct|=(rtrimstr("%")|tonumber) else . end)')
|
||||
liostat=$(/usr/bin/iostat "$(jq -r '.|map(.name)|.[]' <<<"""$jdisks""")" -k -d -p -o JSON)
|
||||
status=$(jq -c --argjson disks "$disks" --argjson iostat "$liostat" 'reduce (.blockdevices[].children[]? |select(.mountpoints? - $disks != .mountpoints) ) as $i ({};.[$i.name] = $i+{iostat:($iostat.sysstat.hosts[0].statistics[0].disk[] | select(.disk_device==$i.name))})' <<<"${blk}")
|
||||
# Send status message
|
||||
shaMessage=$(sha1sum <<<"$status")
|
||||
if [ "$shaOldMessage" = "$shaMessage" ]; then
|
||||
sleepTime=$((sleepTime * 2))
|
||||
[ $sleepTime -gt $MAX_TIMEFRAME ] && sleepTime=$MAX_TIMEFRAME
|
||||
else
|
||||
# Send status message
|
||||
if [ $sleepTime -gt $AVG_TIMEFRAME ]; then
|
||||
sleepTime=$((sleepTime / 2))
|
||||
else
|
||||
sleepTime=$((sleepTime - MIN_TIMEFRAME))
|
||||
fi
|
||||
[ $sleepTime -le $MIN_TIMEFRAME ] && sleepTime=$MIN_TIMEFRAME
|
||||
fi
|
||||
jq -c --arg st "$sleepTime" --arg sh "$shaMessage" '. +
|
||||
{
|
||||
ref: {
|
||||
mws: $st,
|
||||
sha: $sh
|
||||
}
|
||||
}' <<<"${status}" >/tmp/mqtt-hanlder
|
||||
shaOldMessage=$shaMessage
|
||||
# Sleep
|
||||
sleep $sleepTime
|
||||
done
|
||||
fi
|
||||
|
||||
else
|
||||
exec sleep infinity
|
||||
fi
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/mqtt-handler/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/mqtt-handler/type
Normal file
@@ -0,0 +1 @@
|
||||
longrun
|
10
sambanas/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish
Normal file
10
sambanas/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree based on service exit code
|
||||
# ==============================================================================
|
||||
if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
|
||||
bashio::log.warning "nmbd crashed, halting add-on"
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "nmbd stopped"
|
8
sambanas/rootfs/etc/s6-overlay/s6-rc.d/nmbd/run
Normal file
8
sambanas/rootfs/etc/s6-overlay/s6-rc.d/nmbd/run
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# Start nmbd service
|
||||
# ==============================================================================
|
||||
exec nmbd \
|
||||
--foreground \
|
||||
--debug-stdout \
|
||||
--no-process-group
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/nmbd/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/nmbd/type
Normal file
@@ -0,0 +1 @@
|
||||
longrun
|
12
sambanas/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish
Normal file
12
sambanas/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree based on service exit code
|
||||
# ==============================================================================
|
||||
if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
|
||||
bashio::log.warning "smbd crashed, halting add-on"
|
||||
bashio::log.info "Dump SMB configuration:"
|
||||
cat /etc/samba/smb.conf >&2
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "smbd stopped"
|
8
sambanas/rootfs/etc/s6-overlay/s6-rc.d/smbd/run
Normal file
8
sambanas/rootfs/etc/s6-overlay/s6-rc.d/smbd/run
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# Start smbd service
|
||||
# ==============================================================================
|
||||
exec smbd \
|
||||
--foreground \
|
||||
--debug-stdout \
|
||||
--no-process-group
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/smbd/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/smbd/type
Normal file
@@ -0,0 +1 @@
|
||||
longrun
|
10
sambanas/rootfs/etc/s6-overlay/s6-rc.d/wsdd/finish
Normal file
10
sambanas/rootfs/etc/s6-overlay/s6-rc.d/wsdd/finish
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree based on service exit code
|
||||
# ==============================================================================
|
||||
if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
|
||||
bashio::log.warning "wsdd crashed, halting add-on"
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "wsdd stopped"
|
46
sambanas/rootfs/etc/s6-overlay/s6-rc.d/wsdd/run
Normal file
46
sambanas/rootfs/etc/s6-overlay/s6-rc.d/wsdd/run
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# ==============================================================================
|
||||
# Start wsdd service
|
||||
# ==============================================================================
|
||||
declare SMB_GROUP
|
||||
declare SMB_HOST
|
||||
|
||||
SMB_GROUP=$(grep -i '^\s*workgroup\s*=' /etc/samba/smb.conf | cut -f2 -d= | tr -d '[:blank:]')
|
||||
SMB_HOST=$(grep -i '^\s*netbios name\s*=' /etc/samba/smb.conf | cut -f2 -d= | tr -d '[:blank:]')
|
||||
|
||||
if bashio::config.true 'bind_all_interfaces'; then
|
||||
interfaces+=" "
|
||||
elif bashio::config.has_value 'interfaces'; then
|
||||
bashio::log.info "Interfaces from config: $(bashio::config 'interfaces')"
|
||||
for interface in $(bashio::config 'interfaces'); do
|
||||
if [ -d "/sys/class/net/${interface}" ]; then
|
||||
interfaces+=("-i ${interface}")
|
||||
else
|
||||
bashio::log.warning "Interface ${interface} not found, skipping."
|
||||
fi
|
||||
done
|
||||
else
|
||||
# Get supported interfaces
|
||||
for interface in $(bashio::network.interfaces); do
|
||||
interfaces+=("-i ${interface}")
|
||||
done
|
||||
fi
|
||||
|
||||
#if [ ${#interfaces[@]} -eq 0 ]; then
|
||||
# bashio::exit.nok 'No supported interfaces found to bind on.'
|
||||
#fi
|
||||
#bashio::log.info "Interfaces: $(printf '%s ' "${interfaces[@]}")"
|
||||
|
||||
if bashio::config.true 'wsdd2'; then
|
||||
bashio::log.info "Starting the WSDD2 daemon $(printf '%s ' "${interfaces[@]}") for ${SMB_GROUP}/${SMB_HOST}..."
|
||||
setcap CAP_NET_RAW+ep /usr/sbin/wsdd2
|
||||
# shellcheck disable=SC2046
|
||||
exec /usr/sbin/wsdd2 -t -u -w $(printf '%s ' "${interfaces[@]}") -H "${SMB_HOST}" -b vendor:homeassistant,model:sambanas
|
||||
elif bashio::config.true 'wsdd'; then
|
||||
bashio::log.info "Starting the WSDD daemon $(printf '%s ' "${interfaces[@]}") for ${SMB_GROUP}/${SMB_HOST}..."
|
||||
# shellcheck disable=SC2046
|
||||
exec wsdd -v $(printf '%s ' "${interfaces[@]}") -n "${SMB_HOST}" -w "${SMB_GROUP}"
|
||||
else
|
||||
exec sleep infinity
|
||||
fi
|
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/wsdd/type
Normal file
1
sambanas/rootfs/etc/s6-overlay/s6-rc.d/wsdd/type
Normal file
@@ -0,0 +1 @@
|
||||
longrun
|
0
sambanas/rootfs/root/.config/.dont_remove
Normal file
0
sambanas/rootfs/root/.config/.dont_remove
Normal file
23
sambanas/rootfs/usr/local/bin/disklist.py
Normal file
23
sambanas/rootfs/usr/local/bin/disklist.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# python 3.11
|
||||
|
||||
# Return the list of mountable external Devices
|
||||
|
||||
from diskinfo import DiskInfo
|
||||
|
||||
|
||||
di = DiskInfo()
|
||||
disks = di.get_disk_list(sorting=True)
|
||||
regex = r"Name:\s+(\w+)\s.*\n"
|
||||
for d in disks:
|
||||
if d.get_partition_table_type() == "":
|
||||
continue
|
||||
plist = d.get_partition_list()
|
||||
for item in plist:
|
||||
label = item.get_fs_label()
|
||||
if label.startswith("hassos"):
|
||||
continue
|
||||
elif label != "":
|
||||
print(item.get_fs_label())
|
||||
elif item.get_fs_type() == "apfs":
|
||||
print("id:{uuid}".format(uuid=item.get_fs_uuid()))
|
||||
# print(item.get_fs_label()," ",item.get_fs_type()," ",item.get_part_uuid()," ",item.get_name())
|
650
sambanas/rootfs/usr/local/bin/mqtt_daemon.py
Normal file
650
sambanas/rootfs/usr/local/bin/mqtt_daemon.py
Normal file
@@ -0,0 +1,650 @@
|
||||
# python 3.11
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
import time
|
||||
import argparse
|
||||
import collections
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import typing
|
||||
import hashlib
|
||||
from pySMART import DeviceList, Device
|
||||
from pySMART.interface import NvmeAttributes, AtaAttributes
|
||||
import psutil
|
||||
from psutil._common import sdiskio, sdiskusage
|
||||
from ha_mqtt_discoverable import Settings, DeviceInfo
|
||||
from ha_mqtt_discoverable.sensors import Sensor, SensorInfo, BinarySensor
|
||||
from ha_mqtt_discoverable.sensors import BinarySensorInfo
|
||||
import signal
|
||||
from typing import Any, Callable, List, Literal, NoReturn, Self, Tuple, Union
|
||||
import re
|
||||
import humanize
|
||||
from abc import ABC, abstractmethod
|
||||
from diskinfo import Disk
|
||||
|
||||
# config = configparser.ConfigParser( strict=False )
|
||||
# config.read("/etc/samba/smb.conf")
|
||||
|
||||
# Get the arguments from the command-line except the filename
|
||||
ap = argparse.ArgumentParser()
|
||||
|
||||
# Add the arguments to the parser
|
||||
ap.add_argument("-b", "--broker", required=True, help="Broker")
|
||||
ap.add_argument("-p", "--port", required=True, help="Broker Port")
|
||||
ap.add_argument("-u", "--user", required=True, help="Broker User")
|
||||
ap.add_argument("-P", "--password", required=True, help="Broker Password")
|
||||
ap.add_argument("-t", "--topic", required=False, help="Topic", default="sambanas")
|
||||
ap.add_argument(
|
||||
"-i",
|
||||
"--hdidle_log",
|
||||
required=False,
|
||||
help="HD_IDLE log to listen for sleeping drivers",
|
||||
)
|
||||
ap.add_argument(
|
||||
"-T", "--discovery_topic", required=False, help="Topic", default="homeassistant"
|
||||
)
|
||||
ap.add_argument(
|
||||
"-d", "--persist_discovery", required=False, help="Topic", default=True, type=bool
|
||||
)
|
||||
ap.add_argument(
|
||||
"-v", "--addon_version", required=False, help="Addon Version", default="latest"
|
||||
)
|
||||
ap.add_argument(
|
||||
"-l",
|
||||
"--logLevel",
|
||||
required=False,
|
||||
default="WARNING",
|
||||
choices=[
|
||||
"ALL",
|
||||
"TRACE",
|
||||
"DEBUG",
|
||||
"INFO",
|
||||
"NOTICE",
|
||||
"WARNING",
|
||||
"ERROR",
|
||||
"CRITICAL",
|
||||
"FATAL",
|
||||
"OFF",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
args: dict[str, Any] = vars(ap.parse_args())
|
||||
|
||||
|
||||
match str(args["logLevel"]).upper():
|
||||
case "DEBUG" | "ALL" | "TRACE":
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
case "NOTICE":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
case "WARNING" | "INFO":
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
case "ERROR":
|
||||
logging.basicConfig(level=logging.ERROR)
|
||||
case "CRITICAL" | "FATAL":
|
||||
logging.basicConfig(level=logging.CRITICAL)
|
||||
case "OFF":
|
||||
logging.basicConfig(level=logging.NOTSET)
|
||||
case "_":
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
mqtt_settings = Settings.MQTT(
|
||||
host=args["broker"],
|
||||
port=int(args["port"]),
|
||||
username=args["user"],
|
||||
password=args["password"],
|
||||
discovery_prefix=args["discovery_topic"],
|
||||
state_prefix=args["topic"],
|
||||
)
|
||||
|
||||
|
||||
# Global Sensors regitry
|
||||
class ConfigEntity(ABC):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
self.sensorInfo: SensorInfo | BinarySensorInfo = sensorInfo
|
||||
self.state_function = state_function
|
||||
self.attributes_function = attributes_function
|
||||
self.sensor: Union[Sensor, BinarySensor] = None # type: ignore
|
||||
|
||||
def createSensor(self) -> Self:
|
||||
if self.sensor is not None:
|
||||
return self.sensor # type: ignore
|
||||
settings = Settings(mqtt=mqtt_settings, entity=self.sensorInfo)
|
||||
if isinstance(self.sensorInfo, BinarySensorInfo):
|
||||
self.sensor = BinarySensor(settings) # type: ignore
|
||||
logging.debug(
|
||||
"BinarySensor '%s' created", self.sensor.generate_config()["name"]
|
||||
)
|
||||
elif isinstance(self.sensorInfo, SensorInfo):
|
||||
self.sensor = Sensor(settings) # type: ignore
|
||||
logging.debug("Sensor '%s' created", self.sensor.generate_config()["name"])
|
||||
return self
|
||||
|
||||
@abstractmethod
|
||||
def detstroy(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class ConfigEntityAutonomous(ConfigEntity):
|
||||
def detstroy(self) -> None:
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
class ConfigEntityFromDevice(ConfigEntity):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
device: Device,
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] = None, # type: ignore
|
||||
):
|
||||
super().__init__(sensorInfo, state_function, attributes_function)
|
||||
self.device = device
|
||||
|
||||
def detstroy(self) -> None:
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
class ConfigEntityFromHDIdle(ConfigEntity):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
device: Device,
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] = None, # type: ignore
|
||||
):
|
||||
super().__init__(sensorInfo, state_function, attributes_function)
|
||||
self.device = device
|
||||
|
||||
def detstroy(self) -> None:
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
class ConfigEntityFromIoStat(ConfigEntity):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
iostat_device: str,
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
super().__init__(sensorInfo, state_function, attributes_function)
|
||||
self.iostat_device: str = iostat_device
|
||||
self._iostat: collections.deque[tuple[int, dict[str, sdiskio] | None]] = (
|
||||
collections.deque([(0, None), (0, None)], maxlen=2)
|
||||
)
|
||||
|
||||
@property
|
||||
def iostat(self) -> tuple[int, dict[str, sdiskio] | None]:
|
||||
return self._iostat[1]
|
||||
|
||||
@property
|
||||
def h_iostat(self) -> tuple[int, dict[str, sdiskio] | None]:
|
||||
return self._iostat[0]
|
||||
|
||||
def addIostat(self, iostat: dict) -> None:
|
||||
self._iostat.append((time.time_ns(), iostat.copy()))
|
||||
|
||||
def detstroy(self) -> None:
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
class ConfigEntityFromSamba(ConfigEntity):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
samba: dict,
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
super().__init__(sensorInfo, state_function, attributes_function)
|
||||
self.samba = samba
|
||||
|
||||
def detstroy(self):
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
def sambaMetricCollector() -> dict[str, Any]:
|
||||
# smbstatus gets report of current samba server connections
|
||||
try:
|
||||
p = subprocess.Popen(["smbstatus", "-jf"], stdout=subprocess.PIPE)
|
||||
output, err = p.communicate()
|
||||
jsondata = json.loads(output.decode())
|
||||
|
||||
logging.debug("SmbClient: %s", jsondata)
|
||||
except Exception:
|
||||
logging.warning("Exception on smbstat comunication!")
|
||||
jsondata = {}
|
||||
|
||||
data = {"samba_version": jsondata.get("version", "Unknown")}
|
||||
if "sessions" in jsondata:
|
||||
data["users"] = len(jsondata["sessions"])
|
||||
data["users_json"] = jsondata["sessions"]
|
||||
else:
|
||||
data["users"] = 0
|
||||
data["users_json"] = {}
|
||||
|
||||
data["connections"] = len(jsondata["tcons"]) if "tcons" in jsondata else 0
|
||||
if "open_files" in jsondata:
|
||||
data["open_files"] = len(jsondata["open_files"])
|
||||
else:
|
||||
data["open_files"] = 0
|
||||
|
||||
logging.debug(data)
|
||||
return data
|
||||
|
||||
|
||||
sensorList: List[Tuple[str, ConfigEntity]] = []
|
||||
devicePowerStatus: dict[str, str] = {}
|
||||
|
||||
# Main device SambaNas
|
||||
samba: dict[str, Any] = sambaMetricCollector()
|
||||
sambanas_device_info = DeviceInfo(
|
||||
name="SambaNas",
|
||||
model="Addon",
|
||||
manufacturer="@Dianlight",
|
||||
sw_version=samba["samba_version"],
|
||||
hw_version=args["addon_version"],
|
||||
identifiers=[os.getenv("HOSTNAME", default="local_test")],
|
||||
)
|
||||
|
||||
devlist = DeviceList()
|
||||
psdata: dict[str, sdiskio] = psutil.disk_io_counters(perdisk=True, nowrap=True)
|
||||
|
||||
for dev_name in psdata.keys():
|
||||
if re.search(r"\d+$", dev_name):
|
||||
continue
|
||||
dev = Device(dev_name)
|
||||
disk_device_info = DeviceInfo(
|
||||
name=f"SambaNas Disk {dev_name}",
|
||||
model=dev.model,
|
||||
sw_version=dev.firmware,
|
||||
# connections=[[dev_name,sambanas_device_info.identifiers[0]]],
|
||||
identifiers=[dev.serial or "Unknown(%s)" % dev_name],
|
||||
via_device=sambanas_device_info.identifiers[0], # type: ignore
|
||||
)
|
||||
|
||||
# sambanas_device_info.connections.append([dev_name,disk_device_info.identifiers[0]])
|
||||
|
||||
def smartAssesmentAttribute(ce: ConfigEntityFromDevice) -> dict[str, Any]:
|
||||
attributes: dict[str, Any] = {
|
||||
"smart_capable": ce.device.smart_capable,
|
||||
"smart_enabled": ce.device.smart_enabled,
|
||||
"assessment": ce.device.assessment,
|
||||
"messages": ce.device.messages,
|
||||
"rotation_rate": ce.device.rotation_rate,
|
||||
"_test_running": ce.device._test_running,
|
||||
"_test_progress": ce.device._test_progress,
|
||||
}
|
||||
if ce.device.if_attributes is None:
|
||||
return attributes
|
||||
if isinstance(ce.device.if_attributes, AtaAttributes):
|
||||
atattrs: AtaAttributes = ce.device.if_attributes
|
||||
for atattr in atattrs.legacyAttributes:
|
||||
if atattr is None:
|
||||
continue
|
||||
attributes[atattr.name] = atattr.raw
|
||||
health_value: Literal["OK", "FAIL"] = (
|
||||
"OK"
|
||||
if (atattr.thresh is not None and atattr.worst > atattr.thresh)
|
||||
else "FAIL"
|
||||
)
|
||||
attributes[f"{atattr.name}_Health"] = health_value
|
||||
elif isinstance(ce.device.if_attributes, NvmeAttributes):
|
||||
nwmattrs: NvmeAttributes = ce.device.if_attributes
|
||||
for nwmattr in nwmattrs.__dict__.keys():
|
||||
if nwmattrs.__dict__[nwmattr] is None:
|
||||
continue
|
||||
attributes[nwmattr] = nwmattrs.__dict__[nwmattr]
|
||||
return attributes
|
||||
|
||||
if dev.smart_capable:
|
||||
smartAssessment = ConfigEntityFromDevice(
|
||||
sensorInfo=BinarySensorInfo(
|
||||
name=f"S.M.A.R.T {dev.name}",
|
||||
unique_id=hashlib.md5(
|
||||
f"S.M.A.R.T {dev.name}".encode("utf-8")
|
||||
).hexdigest(),
|
||||
device=disk_device_info,
|
||||
# enabled_by_default= dev.smart_capable
|
||||
device_class="problem",
|
||||
),
|
||||
state_function=lambda ce: ce.device.assessment != "PASS",
|
||||
attributes_function=smartAssesmentAttribute,
|
||||
device=dev,
|
||||
)
|
||||
sensorList.append((f"smart_{dev.name}", smartAssessment.createSensor()))
|
||||
|
||||
if args["hdidle_log"] is not None:
|
||||
hdIdleAssessment = ConfigEntityFromHDIdle(
|
||||
sensorInfo=BinarySensorInfo(
|
||||
name=f"POWER {dev.name}",
|
||||
unique_id=hashlib.md5(f"POWER {dev.name}".encode("utf-8")).hexdigest(),
|
||||
device=disk_device_info,
|
||||
device_class="power",
|
||||
),
|
||||
state_function=lambda ce: devicePowerStatus.get(ce.device.name) != "spindown",
|
||||
attributes_function=lambda ce: {"pipe_file": args["hdidle_log"] + "s"},
|
||||
device=dev,
|
||||
)
|
||||
sensorList.append((f"power_{dev.name}", hdIdleAssessment.createSensor()))
|
||||
|
||||
def totalDiskRate(ce: ConfigEntityFromIoStat) -> float | Literal[0]:
|
||||
|
||||
if (
|
||||
ce.h_iostat[0] in [0, ce.iostat[0]] or ce.iostat[1] is None or ce.h_iostat[1] is None
|
||||
):
|
||||
return 0
|
||||
t_read: int = int(ce.iostat[1][ce.iostat_device].read_bytes) - int(
|
||||
ce.h_iostat[1][ce.iostat_device].read_bytes
|
||||
)
|
||||
t_write: int = int(ce.iostat[1][ce.iostat_device].write_bytes) - int(
|
||||
ce.h_iostat[1][ce.iostat_device].write_bytes
|
||||
)
|
||||
t_ns_time: int = ce.iostat[0] - ce.h_iostat[0]
|
||||
logging.debug("%s %d %d %d", ce.iostat_device, t_read, t_write, t_ns_time)
|
||||
return round(((t_read + t_write) * 1000000000 / t_ns_time) / 1024, 2) # kB/s
|
||||
|
||||
def iostatAttribute(ce: ConfigEntityFromIoStat) -> dict[str, str]:
|
||||
if ce.iostat[1] is None:
|
||||
return {}
|
||||
attributes: dict[str, str] = {
|
||||
key: getattr(ce.iostat[1][ce.iostat_device], key)
|
||||
for key in ce.iostat[1][ce.iostat_device]._fields
|
||||
}
|
||||
return attributes
|
||||
|
||||
diskInfo = ConfigEntityFromIoStat(
|
||||
sensorInfo=SensorInfo(
|
||||
name=f"IOSTAT {dev.name}",
|
||||
unique_id=hashlib.md5(f"IOSTAT {dev.name}".encode("utf-8")).hexdigest(),
|
||||
device=disk_device_info,
|
||||
unit_of_measurement="kB/s",
|
||||
device_class="data_rate",
|
||||
),
|
||||
state_function=totalDiskRate,
|
||||
attributes_function=iostatAttribute,
|
||||
iostat_device=dev.name,
|
||||
)
|
||||
|
||||
sensorList.append((f"iostat_{dev.name}", diskInfo.createSensor()))
|
||||
|
||||
partitionDevices: typing.Dict[str, DeviceInfo] = {}
|
||||
|
||||
for partition in Disk(dev_name).get_partition_list():
|
||||
if (partition.get_fs_label() or partition.get_fs_uuid()) == "":
|
||||
continue
|
||||
if not partition.get_name() in partitionDevices:
|
||||
partitionDevices[partition.get_name()] = DeviceInfo(
|
||||
name=f"SambaNas Partition {partition.get_fs_label() or partition.get_fs_uuid()}",
|
||||
model=partition.get_fs_label() or partition.get_fs_uuid(),
|
||||
manufacturer=partition.get_fs_type(),
|
||||
identifiers=[partition.get_fs_label() or partition.get_fs_uuid()],
|
||||
via_device=disk_device_info.identifiers[0], # type: ignore
|
||||
)
|
||||
try:
|
||||
sdiskparts = list(
|
||||
filter(
|
||||
lambda part: part.device.endswith(partition.get_name()),
|
||||
psutil.disk_partitions(),
|
||||
)
|
||||
)
|
||||
if sdiskparts and sdiskparts[0] and sdiskparts[0].mountpoint:
|
||||
if partitionDevices[partition.get_name()].identifiers is None:
|
||||
partitionDevices[partition.get_name()].identifiers = []
|
||||
if isinstance(partitionDevices[partition.get_name()].identifiers, str):
|
||||
partitionDevices[partition.get_name()].identifiers = [
|
||||
str(partitionDevices[partition.get_name()].identifiers)
|
||||
]
|
||||
partitionDevices[partition.get_name()].identifiers.append( # type: ignore
|
||||
sdiskparts[0].mountpoint
|
||||
)
|
||||
finally:
|
||||
pass
|
||||
|
||||
logging.debug(
|
||||
"Generated %d Partitiond Device for %s", len(partitionDevices), dev.name
|
||||
)
|
||||
|
||||
for partition_device, partitionDeviceInfo in partitionDevices.items():
|
||||
partitionInfo = ConfigEntityFromIoStat(
|
||||
sensorInfo=SensorInfo(
|
||||
name=f"IOSTAT {partitionDeviceInfo.model}",
|
||||
unique_id=hashlib.md5(
|
||||
f"IOSTAT {partitionDeviceInfo.model}".encode("utf-8")
|
||||
).hexdigest(),
|
||||
device=partitionDeviceInfo,
|
||||
unit_of_measurement="kB/s",
|
||||
device_class="data_rate",
|
||||
),
|
||||
state_function=totalDiskRate,
|
||||
attributes_function=iostatAttribute,
|
||||
iostat_device=partition_device,
|
||||
)
|
||||
|
||||
sensorList.append((f"iostat_{partition_device}", partitionInfo.createSensor()))
|
||||
|
||||
def usageAttribute(ce: ConfigEntityAutonomous) -> dict[str, str]:
|
||||
if ce.sensorInfo.device is None or ce.sensorInfo.device.identifiers is None:
|
||||
return {}
|
||||
usage: sdiskusage = psutil.disk_usage(ce.sensorInfo.device.identifiers[-1])
|
||||
attributes: dict[str, str] = {
|
||||
"used": humanize.naturalsize(usage.used),
|
||||
"total": humanize.naturalsize(usage.total),
|
||||
"free": humanize.naturalsize(usage.free),
|
||||
}
|
||||
return attributes
|
||||
|
||||
def partitionUsage(ce: ConfigEntityAutonomous) -> Any:
|
||||
if ce.sensorInfo.device is None or ce.sensorInfo.device.identifiers is None:
|
||||
return
|
||||
logging.debug(
|
||||
"Collecting Usage from %s [%s]",
|
||||
ce.sensorInfo.device.identifiers,
|
||||
ce.sensorInfo.device.identifiers[-1],
|
||||
)
|
||||
return psutil.disk_usage(ce.sensorInfo.device.identifiers[-1]).percent
|
||||
|
||||
if (
|
||||
partitionDeviceInfo.identifiers is not None and len(partitionDeviceInfo.identifiers) > 1
|
||||
):
|
||||
partitionInfo = ConfigEntityAutonomous(
|
||||
sensorInfo=SensorInfo(
|
||||
name=f"Usage {partitionDeviceInfo.model}",
|
||||
unique_id=hashlib.md5(
|
||||
f"Usage {partitionDeviceInfo.model}".encode("utf-8")
|
||||
).hexdigest(),
|
||||
device=partitionDeviceInfo,
|
||||
icon="mdi:harddisk",
|
||||
unit_of_measurement="%",
|
||||
device_class="power_factor",
|
||||
),
|
||||
state_function=partitionUsage,
|
||||
attributes_function=usageAttribute,
|
||||
)
|
||||
|
||||
sensorList.append(
|
||||
(f"usage_{partition_device}", partitionInfo.createSensor())
|
||||
)
|
||||
|
||||
sambaUsers = ConfigEntityFromSamba(
|
||||
sensorInfo=SensorInfo(
|
||||
name="Online Users",
|
||||
device=sambanas_device_info,
|
||||
unique_id=hashlib.md5("Online Users".encode("utf-8")).hexdigest(),
|
||||
),
|
||||
state_function=lambda ce: ce.samba["users"],
|
||||
samba=samba,
|
||||
)
|
||||
sensorList.append(("samba_users", sambaUsers.createSensor()))
|
||||
sambaConnections = ConfigEntityFromSamba(
|
||||
sensorInfo=SensorInfo(
|
||||
name="Active Connections",
|
||||
device=sambanas_device_info,
|
||||
unique_id=hashlib.md5("Active Connections".encode("utf-8")).hexdigest(),
|
||||
),
|
||||
state_function=lambda ce: ce.samba["connections"],
|
||||
attributes_function=lambda ce: {"open_files": ce.samba["open_files"]},
|
||||
samba=samba,
|
||||
)
|
||||
sensorList.append(("samba_connections", sambaConnections.createSensor()))
|
||||
|
||||
tasks: list[asyncio.Task] = []
|
||||
|
||||
|
||||
async def publish_states() -> NoReturn:
|
||||
while True:
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityAutonomous):
|
||||
logging.info("Updating sensor %s", sensor[0])
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1])) # type: ignore
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
|
||||
async def publish_idle_states() -> NoReturn:
|
||||
with open(args["hdidle_log"]) as pipe_hdidle:
|
||||
while True:
|
||||
line = pipe_hdidle.readline()
|
||||
if len(line) == 0:
|
||||
logging.error(f"Pipe Broken {args["hdidle_log"]}!")
|
||||
break
|
||||
# Parse line with ilde status
|
||||
# Aug 8 00:14:55 enterprise hd-idle[9958]: sda spindown
|
||||
# Aug 8 00:14:55 enterprise hd-idle[9958]: sdb spindown
|
||||
# Aug 8 00:14:56 enterprise hd-idle[9958]: sdc spindown
|
||||
# Aug 8 00:17:55 enterprise hd-idle[9958]: sdb spinup
|
||||
# Aug 8 00:28:55 enterprise hd-idle[9958]: sdb spindown
|
||||
disk, status = line.split(' ', maxsplit=1)
|
||||
logging.info("Disk %s change to status %s", disk, status.strip())
|
||||
devicePowerStatus[disk] = status.strip()
|
||||
logging.debug(devicePowerStatus)
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityFromHDIdle) and sensor[1].device.name == disk:
|
||||
logging.info("Updating sensor %s", sensor[0])
|
||||
if isinstance(sensor[1].sensor, BinarySensor):
|
||||
sensor[1].sensor.update_state(sensor[1].state_function(sensor[1]))
|
||||
elif isinstance(sensor[1].sensor, Sensor):
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1])) # type: ignore
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
|
||||
|
||||
async def publish_device_states() -> NoReturn:
|
||||
while True:
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityFromDevice):
|
||||
logging.info(
|
||||
"Updating Device sensor %s (pw:%s)",
|
||||
sensor[0],
|
||||
devicePowerStatus.get(sensor[1].device.name),
|
||||
)
|
||||
|
||||
if devicePowerStatus.get(sensor[1].device.name) == "spindown":
|
||||
continue
|
||||
|
||||
sensor[1].device.update()
|
||||
if isinstance(sensor[1].sensor, BinarySensor):
|
||||
sensor[1].sensor.update_state(sensor[1].state_function(sensor[1]))
|
||||
elif isinstance(sensor[1].sensor, Sensor):
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1]))
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
|
||||
async def publish_iostate_states() -> NoReturn:
|
||||
while True:
|
||||
|
||||
iostate: dict[str, sdiskio] = psutil.disk_io_counters(perdisk=True, nowrap=True)
|
||||
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityFromIoStat):
|
||||
logging.info("Updating Iostat sensor %s", sensor[0])
|
||||
sensor[1].addIostat(iostate)
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1])) # type: ignore
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
async def publish_samba_states() -> NoReturn:
|
||||
while True:
|
||||
samba: dict[str, Any] = sambaMetricCollector()
|
||||
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityFromSamba):
|
||||
logging.info("Updating Samba sensor %s", sensor[0])
|
||||
sensor[1].samba = samba
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1])) # type: ignore
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
await asyncio.sleep(10)
|
||||
|
||||
|
||||
async def run() -> None:
|
||||
|
||||
def doneCallback(task):
|
||||
for sensor in sensorList:
|
||||
logging.info("Unpublish sensor %s", sensor[0])
|
||||
sensor[1].sensor.delete()
|
||||
|
||||
# Loop Status publish
|
||||
async with asyncio.TaskGroup() as tg:
|
||||
if args["hdidle_log"] is not None:
|
||||
task = tg.create_task(publish_idle_states(), name="Read and Publish HD-IDLE states")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
task = tg.create_task(publish_states(), name="Publish States")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
task = tg.create_task(publish_device_states(), name="Publish Device States")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
task = tg.create_task(publish_iostate_states(), name="Publish IO States")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
task = tg.create_task(publish_samba_states(), name="Publish Samba States")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
async def ask_exit(signame):
|
||||
logging.warning("Signal %x. Unpublish %d sensors", signame, len(sensorList))
|
||||
|
||||
loop.remove_signal_handler(signame)
|
||||
|
||||
for task in tasks:
|
||||
try:
|
||||
task.cancel()
|
||||
finally:
|
||||
logging.warning(f"Task {task.get_name()} cancelled!")
|
||||
|
||||
for signame in ('SIGINT', 'SIGTERM', 'SIGHUP'):
|
||||
loop.add_signal_handler(getattr(signal, signame),
|
||||
lambda signame=signame: asyncio.create_task(ask_exit(signame)))
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run())
|
403
sambanas/rootfs/usr/local/bin/poetry.lock
generated
Normal file
403
sambanas/rootfs/usr/local/bin/poetry.lock
generated
Normal file
@@ -0,0 +1,403 @@
|
||||
# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
description = "Reusable constraint types to use with typing.Annotated"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
|
||||
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chardet"
|
||||
version = "5.2.0"
|
||||
description = "Universal encoding detector for Python 3"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
|
||||
{file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diskinfo"
|
||||
version = "3.1.2"
|
||||
description = "Disk information Python library for Linux"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "diskinfo-3.1.2-py3-none-any.whl", hash = "sha256:2b8606462b5783d18188ff1a8b7c5094dbc455e8361418033ffe2a823aa3d4b7"},
|
||||
{file = "diskinfo-3.1.2.tar.gz", hash = "sha256:3f60a6f7b72dbf079c7f828540d38078e977aa5f578aa80a6e50b5860ffeaaa1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pySMART = ">=1.3.0"
|
||||
|
||||
[[package]]
|
||||
name = "gitlike-commands"
|
||||
version = "0.3.0"
|
||||
description = "Makes driver scripts that enable git-like commands so that foo bar will run foo-bar"
|
||||
optional = false
|
||||
python-versions = ">=3.9,<4.0"
|
||||
files = [
|
||||
{file = "gitlike_commands-0.3.0-py3-none-any.whl", hash = "sha256:c262f8f532639ec8558369bdc2cd904bd0b65638834ed333c42a51be69578f21"},
|
||||
{file = "gitlike_commands-0.3.0.tar.gz", hash = "sha256:72f4e65239cb6a4a2c614867c5f914b5d5994edd2863335515b543689b01ff70"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ha-mqtt-discoverable"
|
||||
version = "0.19.2"
|
||||
description = "Python library for creating MQTT entities compatible with Home Assistant"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.10.0"
|
||||
files = [
|
||||
{file = "ha_mqtt_discoverable-0.19.2-py3-none-any.whl", hash = "sha256:84725816a53d4e64f9d81cac6493c60dbd73899300c169b978fff9fdcbae2344"},
|
||||
{file = "ha_mqtt_discoverable-0.19.2.tar.gz", hash = "sha256:2c0facdfdff5573a4bae7ab40e9b66cc077e65445fb9d6f356e1c74ce00aa9d9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
gitlike-commands = ">=0.2.1,<0.4.0"
|
||||
paho-mqtt = "2.1.0"
|
||||
pyaml = "25.5.0"
|
||||
pydantic = "2.11.5"
|
||||
|
||||
[[package]]
|
||||
name = "humanfriendly"
|
||||
version = "10.0"
|
||||
description = "Human friendly output for text interfaces using Python"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
{file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
|
||||
{file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "humanize"
|
||||
version = "4.12.3"
|
||||
description = "Python humanize utilities"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "humanize-4.12.3-py3-none-any.whl", hash = "sha256:2cbf6370af06568fa6d2da77c86edb7886f3160ecd19ee1ffef07979efc597f6"},
|
||||
{file = "humanize-4.12.3.tar.gz", hash = "sha256:8430be3a615106fdfceb0b2c1b41c4c98c6b0fc5cc59663a5539b111dd325fb0"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["freezegun", "pytest", "pytest-cov"]
|
||||
|
||||
[[package]]
|
||||
name = "paho-mqtt"
|
||||
version = "2.1.0"
|
||||
description = "MQTT version 5.0/3.1.1 client class"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "paho_mqtt-2.1.0-py3-none-any.whl", hash = "sha256:6db9ba9b34ed5bc6b6e3812718c7e06e2fd7444540df2455d2c51bd58808feee"},
|
||||
{file = "paho_mqtt-2.1.0.tar.gz", hash = "sha256:12d6e7511d4137555a3f6ea167ae846af2c7357b10bc6fa4f7c3968fc1723834"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
proxy = ["pysocks"]
|
||||
|
||||
[[package]]
|
||||
name = "psutil"
|
||||
version = "7.0.0"
|
||||
description = "Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25"},
|
||||
{file = "psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da"},
|
||||
{file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91"},
|
||||
{file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34"},
|
||||
{file = "psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993"},
|
||||
{file = "psutil-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:84df4eb63e16849689f76b1ffcb36db7b8de703d1bc1fe41773db487621b6c17"},
|
||||
{file = "psutil-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e744154a6580bc968a0195fd25e80432d3afec619daf145b9e5ba16cc1d688e"},
|
||||
{file = "psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99"},
|
||||
{file = "psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"},
|
||||
{file = "psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["abi3audit", "black (==24.10.0)", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"]
|
||||
test = ["pytest", "pytest-xdist", "setuptools"]
|
||||
|
||||
[[package]]
|
||||
name = "pyaml"
|
||||
version = "25.5.0"
|
||||
description = "PyYAML-based module to produce a bit more pretty and readable YAML-serialized data"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyaml-25.5.0-py3-none-any.whl", hash = "sha256:b9e0c4e58a5e8003f8f18e802db49fd0563ada587209b13e429bdcbefa87d035"},
|
||||
{file = "pyaml-25.5.0.tar.gz", hash = "sha256:5799560c7b1c9daf35a7a4535f53e2c30323f74cbd7cb4f2e715b16dd681a58a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
PyYAML = "*"
|
||||
|
||||
[package.extras]
|
||||
anchors = ["unidecode"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.11.5"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7"},
|
||||
{file = "pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.6.0"
|
||||
pydantic-core = "2.33.2"
|
||||
typing-extensions = ">=4.12.2"
|
||||
typing-inspection = ">=0.4.0"
|
||||
|
||||
[package.extras]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
timezone = ["tzdata"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.33.2"
|
||||
description = "Core functionality for Pydantic validation and serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"},
|
||||
{file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pyreadline3"
|
||||
version = "3.5.4"
|
||||
description = "A python implementation of GNU readline."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"},
|
||||
{file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["build", "flake8", "mypy", "pytest", "twine"]
|
||||
|
||||
[[package]]
|
||||
name = "pysmart"
|
||||
version = "1.4.1"
|
||||
description = "Wrapper for smartctl (smartmontools)"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pySMART-1.4.1-py3-none-any.whl", hash = "sha256:8bb92d0bb579a073c60dca60cb69eea6516d7cf2673ad6d149d2a49e61432e5d"},
|
||||
{file = "pysmart-1.4.1.tar.gz", hash = "sha256:65700612477861acd83550c33a9430933017c93d91f66973ed409696b0327723"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
chardet = "*"
|
||||
humanfriendly = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["coveralls", "pdoc", "pytest", "pytest-cov"]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.2"
|
||||
description = "YAML parser and emitter for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
|
||||
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-inspection"
|
||||
version = "0.4.0"
|
||||
description = "Runtime typing introspection tools"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"},
|
||||
{file = "typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.12.0"
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "13b19a408fb9cc0752b3e7d593791056598fe9ab78303fef118e37a7b6a3836f"
|
21
sambanas/rootfs/usr/local/bin/pyproject.toml
Normal file
21
sambanas/rootfs/usr/local/bin/pyproject.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[tool.poetry]
|
||||
name = "sambanas-util"
|
||||
version = "1.0.1"
|
||||
description = "Utility for SambaNas Addon"
|
||||
authors = ["dianlight <lucio.tarantino@gmail.com>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
pySMART = "^1.3.0"
|
||||
psutil = "^7.0.0"
|
||||
humanize = "^4.9.0"
|
||||
diskinfo = "^3.1.1"
|
||||
ha-mqtt-discoverable = "^0.19.0"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
155
sambanas/rootfs/usr/share/tempio/smb.gtpl
Normal file
155
sambanas/rootfs/usr/share/tempio/smb.gtpl
Normal file
@@ -0,0 +1,155 @@
|
||||
[global]
|
||||
{{ if .compatibility_mode }}
|
||||
client min protocol = NT1
|
||||
server min protocol = NT1
|
||||
{{ else }}
|
||||
server min protocol = SMB2_10
|
||||
client min protocol = SMB2_10
|
||||
{{ end }}
|
||||
|
||||
{{if .multi_channel }}
|
||||
server multi channel support = yes
|
||||
aio read size = 1
|
||||
aio write size = 1
|
||||
{{ end }}
|
||||
|
||||
dns proxy = yes
|
||||
|
||||
ea support = yes
|
||||
vfs objects = catia fruit streams_xattr{{ if .recyle_bin_enabled }} recycle{{ end }}
|
||||
fruit:aapl = yes
|
||||
fruit:model = MacSamba
|
||||
|
||||
fruit:resource = file
|
||||
fruit:veto_appledouble = no
|
||||
fruit:posix_rename = yes
|
||||
fruit:wipe_intentionally_left_blank_rfork = yes
|
||||
fruit:zero_file_id = yes
|
||||
fruit:delete_empty_adfiles = yes
|
||||
|
||||
# cherry pick from PR#167 to Test
|
||||
fruit:copyfile = yes
|
||||
fruit:nfs_aces = no
|
||||
|
||||
# Performance Enhancements for network
|
||||
socket options = TCP_NODELAY IPTOS_LOWDELAY
|
||||
min receivefile size = 16384
|
||||
getwd cache = yes
|
||||
aio read size = 1
|
||||
aio write size = 1
|
||||
# End PR#167
|
||||
|
||||
netbios name = {{ env "HOSTNAME" }}
|
||||
workgroup = {{ .workgroup }}
|
||||
server string = Samba NAS HomeAssistant config
|
||||
local master = {{ .local_master | ternary "yes" "no" }}
|
||||
multicast dns register = {{ if or .wsdd .wsdd2 }}no{{ else }}yes{{ end }}
|
||||
|
||||
security = user
|
||||
ntlm auth = yes
|
||||
idmap config * : backend = tdb
|
||||
idmap config * : range = 1000000-2000000
|
||||
|
||||
load printers = no
|
||||
disable spoolss = yes
|
||||
|
||||
{{ $log_level := dict "trace" "5" "debug" "4" "info" "3" "notice" "2" "warning" "1" "error" "1" "fatal" "1" -}}
|
||||
log level = {{ .log_level | default "warning" | get $log_level }}
|
||||
|
||||
bind interfaces only = {{ .bind_all_interfaces | default false | ternary "no" "yes" }}
|
||||
interfaces = 127.0.0.1 {{ .interfaces | join " " }} {{ .docker_interface | default " "}}
|
||||
hosts allow = 127.0.0.1 {{ .allow_hosts | join " " }} {{ .docker_net | default " " }}
|
||||
|
||||
mangled names = no
|
||||
dos charset = CP1253
|
||||
unix charset = UTF-8
|
||||
|
||||
{{ define "SHT" }}
|
||||
{{- $unsupported := list "vfat" "msdos" "f2fs" "fuseblk" "exfat" -}}
|
||||
{{- $rosupported := list "apfs"}}
|
||||
{{- $name := regexReplaceAll "[^A-Za-z0-9_/ ]" .share "_" | regexFind "[A-Za-z0-9_ ]+$" | upper -}}
|
||||
{{- $dinfo := get .shares $name | default dict -}}
|
||||
[{{- $name -}}]
|
||||
browseable = yes
|
||||
writeable = {{ has $dinfo.fs $rosupported | ternary "no" "yes" }}
|
||||
|
||||
# cherry pick from PR#167 to Test
|
||||
create mask = 0664
|
||||
force create mode = 0664
|
||||
directory mask = 0775
|
||||
force directory mode = 0775
|
||||
# End PR#167
|
||||
|
||||
path = /{{- if eq .share "config" }}homeassistant{{- else }}{{- .share }}{{- end }}
|
||||
valid users =_ha_mount_user_ {{ .users|default .username|join " " }} {{ .ro_users|join " " }}
|
||||
{{ if .ro_users }}
|
||||
read list = {{ .ro_users|join " " }}
|
||||
{{ end }}
|
||||
force user = root
|
||||
force group = root
|
||||
veto files = /{{ .veto_files | join "/" }}/
|
||||
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }}
|
||||
|
||||
# DEBUG: {{ toJson $dinfo }}|.share={{ .share }}|$name={{ $name }}|.shares={{ .shares }}|
|
||||
|
||||
{{if .recyle_bin_enabled }}
|
||||
recycle:repository = .recycle/%U
|
||||
recycle:keeptree = yes
|
||||
recycle:versions = yes
|
||||
recycle:touch = yes
|
||||
recycle:touch_mtime = no
|
||||
recycle:directory_mode = 0777
|
||||
#recycle:subdir_mode = 0700
|
||||
#recycle:exclude =
|
||||
#recycle:exclude_dir =
|
||||
#recycle:maxsize = 0
|
||||
{{ end }}
|
||||
|
||||
# TM:{{ if has $dinfo.fs $unsupported }}unsupported{{else}}{{ .timemachine }}{{ end }} US:{{ .users|default .username|join "," }} {{ .ro_users|join "," }}{{- if .medialibrary.enable }}{{ if .usage }} CL:{{ .usage }}{{ end }} FS:{{ $dinfo.fs | default "native" }} {{ if .recyle_bin_enabled }}RECYCLEBIN{{ end }} {{ end }}
|
||||
{{- if and .timemachine (has $dinfo.fs $unsupported | not ) }}
|
||||
vfs objects = catia fruit streams_xattr{{ if .recyle_bin_enabled }} recycle{{ end }}
|
||||
|
||||
# Time Machine Settings Ref: https://github.com/markthomas93/samba.apple.templates
|
||||
fruit:time machine = yes
|
||||
#fruit:time machine max size = SIZE [K|M|G|T|P]
|
||||
fruit:metadata = stream
|
||||
{{ end }}
|
||||
{{- if has $dinfo.fs $unsupported }}
|
||||
vfs objects = catia{{ if .recyle_bin_enabled }} recycle{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{- $dfdisk := list "config" "addons" "ssl" "share" "backup" "media" "addon_configs" }}
|
||||
{{- $disks := concat $dfdisk (compact .moredisks|default list) -}}
|
||||
{{- $root := . -}}
|
||||
{{- range $disk := $disks -}}
|
||||
{{- $acld := false -}}
|
||||
{{- range $dd := $root.acl -}}
|
||||
{{- $ndisk := $disk | regexFind "[A-Za-z0-9_]+$" -}}
|
||||
{{- if eq ($dd.share|upper) ($ndisk|upper) -}}
|
||||
{{- $def := deepCopy $dd }}
|
||||
{{- $acld = true -}}
|
||||
{{- if not $dd.disabled -}}
|
||||
{{- $_ := set $dd "share" $disk -}}
|
||||
{{- if has $disk $dfdisk -}}
|
||||
{{- $_ := set $def "timemachine" false -}}
|
||||
{{- $_ := set $def "usage" "" -}}
|
||||
{{- else -}}
|
||||
{{- $_ := set $def "timemachine" true -}}
|
||||
{{- $_ := set $def "usage" "media" -}}
|
||||
{{- end }}
|
||||
{{- template "SHT" deepCopy $root | mergeOverwrite $def $dd -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if not $acld -}}
|
||||
{{- $dd := dict "share" $disk "timemachine" true -}}
|
||||
{{- $_ := set $dd "usage" "media" -}}
|
||||
{{- if has $disk $dfdisk -}}
|
||||
{{- $_ := set $dd "timemachine" false -}}
|
||||
{{- $_ := set $dd "usage" "" -}}
|
||||
{{- end }}
|
||||
{{- template "SHT" (deepCopy $root | mergeOverwrite $dd) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
5
sambanas/test/buildLocal.sh
Normal file
5
sambanas/test/buildLocal.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#! /bin/bash
|
||||
# onetime when docker upgrade
|
||||
#docker run --rm --privileged multiarch/qemu-user-static:register
|
||||
docker build --build-arg BUILD_FROM="homeassistant/armv7-base:3.13" --build-arg CLI_VERSION="4.13.0" --build-arg BUILD_ARCH="armv7" -t dianlight/armv7-addon-sambanas .. && \
|
||||
docker push dianlight/armv7-addon-sambanas:latest
|
9
sambanas/test/options.json
Normal file
9
sambanas/test/options.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"workgroup": "WORKGROUP",
|
||||
"username": "homeassistant",
|
||||
"password": "test",
|
||||
"interface": "",
|
||||
"moredisks": ["TIMEMACHINE", "LIBRARY"],
|
||||
"allow_hosts": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
|
||||
"veto_files": ["._*", ".DS_Store", "Thumbs.db", "icon?", ".Trashes"]
|
||||
}
|
5
sambanas/test/runLocal.sh
Normal file
5
sambanas/test/runLocal.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#! /bin/bash
|
||||
mkdir -p /tmp/my_test_data
|
||||
cp options.json /tmp/my_test_data
|
||||
docker build --build-arg BUILD_FROM="homeassistant/armv7-base:latest" -t dianlight/armv7-addon-sambanas ..
|
||||
docker run --rm -v /tmp/my_test_data:/data -p 5300 dianlight/armv7-addon-sambanas
|
97
sambanas/translations/en.yaml
Normal file
97
sambanas/translations/en.yaml
Normal file
@@ -0,0 +1,97 @@
|
||||
---
|
||||
configuration:
|
||||
username:
|
||||
name: Username
|
||||
description: >-
|
||||
The username you would like to use to authenticate with the Samba server.
|
||||
password:
|
||||
name: Password
|
||||
description: >-
|
||||
The password that goes with the username configured for authentication.
|
||||
workgroup:
|
||||
name: Workgroup
|
||||
description: Change WORKGROUP to reflect your network needs.
|
||||
local_master:
|
||||
name: Local master
|
||||
description: Enable to try and become a local master browser on a subnet.
|
||||
enabled_shares:
|
||||
name: >-
|
||||
Enabled Shares - allowed values are:
|
||||
addons, addon_configs, backup, config, media, share, or ssl.
|
||||
description: >-
|
||||
List of file shares to make available.
|
||||
Adding a share requires typing its name to add it.
|
||||
The listed values are the only allowed values.
|
||||
The configuration cannot be saved if any non-allowed value is in the list.
|
||||
compatibility_mode:
|
||||
name: Enable Compatibility Mode
|
||||
description: >-
|
||||
Enable this to use old legacy Samba protocols on the Samba add-on.
|
||||
veto_files:
|
||||
name: Veto Files
|
||||
description: List of files that are neither visible nor accessible.
|
||||
allow_hosts:
|
||||
name: Allowed Hosts
|
||||
description: List of hosts/networks allowed to access the shared folders.
|
||||
automount:
|
||||
name: Enable Automatic Mount
|
||||
description: Automatic mount and expose all labeled disk.
|
||||
moredisks:
|
||||
name: List of labeled disk to mount
|
||||
description: List of disks or partitions label to search and share. It is also possible to use the disk id if you prepend the name with `id:`
|
||||
available_disks_log:
|
||||
name: Enable discovered disk log
|
||||
description: Enable the log of found labeled disk. Usefull for initial configuration.
|
||||
medialibrary:
|
||||
name: Configure the mount in media path
|
||||
description: Enable the visibility of `moredisk` on /media path.
|
||||
recyle_bin_enabled:
|
||||
name: Enable recyle_bin on share
|
||||
description: Allow client SO to use Recycle Bin functionality on share
|
||||
wsdd:
|
||||
name: Enable the use of external WSDD daemon
|
||||
description: Setting this option to `true` will enable the use of wsdd over internal samba system.
|
||||
wsdd2:
|
||||
name: Enable the use of Netgear WSDD daemon
|
||||
description: Setting this option to `true` will enable the use of wsdd2 over wsdd. Set to true if you have trouble to see the disk on Windows 11+
|
||||
hdd_idle_seconds:
|
||||
name: Set the timeout for hd-idle demon
|
||||
description: Idle time in seconds for all disks. Setting this value to 0 will never spin down the disk(s).
|
||||
enable_smart:
|
||||
name: Enable SMART on all disks
|
||||
description: Enable automatic offline testing every four hours, and enable autosaving of SMART Attributes.
|
||||
multi_channel:
|
||||
name: Enable Samba Multichannel support
|
||||
description:
|
||||
Multi-Channel is an SMB3 protocol feature that allows the client
|
||||
to bind multiple transport connections into one authenticated
|
||||
SMB session. This allows for increased fault tolerance and
|
||||
throughput. The client chooses transport connections as reported
|
||||
by the server and also chooses over which of the bound transport
|
||||
connections to send traffic. I/O operations for a given file
|
||||
handle can span multiple network connections this way.
|
||||
An SMB multi-channel session will be valid as long as at least
|
||||
one of its channels are up.
|
||||
mqtt_nexgen_entities:
|
||||
name: Enable the use of nexgen MQTT implementation
|
||||
description: Setting this option to `true` will expose mqtt new entities. This is a refactor that allow to use less CPU.
|
||||
mqtt_enable:
|
||||
name: Enable the exposition of disk information via MQTT
|
||||
description: Setting this option to `true` will enable the use of mqtt to send disks status data.
|
||||
autodiscovery:
|
||||
name: "Autodiscovery options"
|
||||
disable_discovery:
|
||||
name: Enable the automatic MQTT messages
|
||||
description: Setting this option to `true` will disable the sending of Auto Discovery MQTT messages. You need to configure MQTT sensors manually
|
||||
other_users:
|
||||
name: List of other user to create
|
||||
description: Create more use for SMB/CIFS access
|
||||
acl:
|
||||
name: Access Lists
|
||||
description: SMB/CIFS share access lists
|
||||
interfaces:
|
||||
name: network interfaces
|
||||
description: List of network interface to bind
|
||||
bind_all_interfaces:
|
||||
name: Enable the use of all network interfaces
|
||||
description: Force Samba to bind on all network interface. This is usefull for pseudo-ethernet devices like TailScale
|
Reference in New Issue
Block a user