This commit is contained in:
ai-dev
2025-10-11 12:14:55 +02:00
parent 0085404253
commit e8681cdead
93 changed files with 3680 additions and 671 deletions

5
samba/.hadolint.yaml Normal file
View File

@@ -0,0 +1,5 @@
ignored:
- DL3003
- DL3006
- DL3018
- DL3059

View File

@@ -1,146 +1,644 @@
# Changelog # Changelog
## 12.5.2 ## 12.5.0-nas [ Maintenance Mode ]
- Avoid binding to disabled network interfaces ### ✨ Features
## 12.5.1 ### 🚨 Important Notice Regarding SambaNas Addon Development
- Add configurations option to disable Apple devices interoperability. Disabling this setting might be required for file systems that do not support extended attributes such as exFAT. **SambaNas Addon is Now in Maintenance Mode**
## 12.5.0 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.
- Add the ability to enable and disable trying to become a local master browser on a subnet **Introducing SambaNas2: The Future of Samba Integration**
## 12.4.0 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.
- Add the ability to enable and disable specific shares, improving user control over folder access **Current Status and Upcoming Beta Release**
## 12.3.3 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.
- Enable Samba configurations to improve interoperability with Apple devices 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.
## 12.3.2 [Add our Hass.io BETA add-ons repository][beta-repository] to your Hass.io instance.
- Suppress benign idmap logged error ### 🩹 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)
## 12.3.1 ### 🏗 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)
- Handle passwords with backslash correctly [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.0 ## 12.3.2-nas1
- Upgrade Alpine Linux to 3.19 ### 🩹 BugFix
## 12.2.0 - Build for armv7 arch Fix: [#288](https://github.com/dianlight/hassio-addons/issues/288)]
- Decrease Samba log level ### 🏗 Chore
## 12.1.0 - 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
- Use the new Home Assistant folder for the `config` share ## 12.3.2-nas
- Add support for accessing public add-on configurations
## 12.0.0 ### ✨ Features
- Temporary remove access to add-on config shares, until Supervisor 2023.11.2 has been rolled out stable - Allow use of samba multicast dns register
- Revert `config` share name change to avoid user facing change - New `wsdd` option to enable/disable wsdd
- Adjust location of Home Assistant config to match latest dev/beta Supervisor - New Sensor `Power` if you enable `hdd_idle_seconds` option in config
- Migrate add-on layout to S6 Overlay - New Option `multi_channel` to Enable multi-channel in smb.conf [#262](https://github.com/dianlight/hassio-addons/issues/262)
## 11.0.0 ### 🩹 BugFix
- The `config` share has been renamed to `homeassistant` to match upstream changes. - Fix Startup/Shutdown sequence [#252](https://github.com/dianlight/hassio-addons/issues/252)
- Add support for accessing public add-on configurations - Fix ACL miss on mixed-case disk's labels [#257](https://github.com/dianlight/hassio-addons/issues/257)
- Update to Alpine 3.18 - Fix passwords with spaces [#251](https://github.com/dianlight/hassio-addons/issues/251)
- Adds HEALTCHECK support - `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)
## 10.0.2 ### 🏗 Chore
- Enable IPv6 ULA and IPv4 link-local addresses by default - [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
## 10.0.1 ### 👁️ Known Issue
- Update to Alpine 3.17 - MQTT Entities sometime are not deleted on close
## 10.0.0 [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
BREAKING CHANGE: Don't mangle filenames ## 12.2.0-nas2
By default, Samba mangles filenames with special characters to ensure ### ✨ Features
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 - 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)
systems do not have these restrictions.
### 🩹 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
- Don't mangle filenames (fixes #2541)
- Upgrade Alpine Linux to 3.16 - Upgrade Alpine Linux to 3.16
## 9.7.0 ### 🩹 BugFix
- Upgrade Alpine Linux to 3.15 - AVAHI Support hostname with dot
- Sign add-on with Codenotary Community Attestation Service (CAS)
## 9.6.1 ## 9.7.0-nas
- Remove lo from interface list ### ✨ Features
- Exit with error if there are no supported interfaces to run Samba on
## 9.6.0 - Add btrfs support (PR #75 By @fAuernigg)
- Run on all supported interfaces ### 🩹 BugFix
## 9.5.1 - Change startup to system (PR #81 By @marciogranzotto)
- Add `hassio_api` to add-on configuration ### 🏗 Chore
## 9.5.0 - [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
- Remove interface options in favor of network [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.4.0 ## 9.5.1-nas4
- Upgrade Alpine Linux to 3.13 ### ✨ Features
- Rewrite configuration generation code
## 9.3.1 - Lovely initial Banner!
- New Option `available_disks_log` to turn on/off the list of available Labeled disk in log
- Update options schema for passwords ### 🩹 BugFix
## 9.3.0 - 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 - Support new media folder
- Update Samba to 4.12.6 - Update Samba to 4.12.6
- Upgrade Alpine Linux to 3.12 - Upgrade Alpine Linux to 3.12
## 9.2.0 [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 - Pin base image version
- Rewrite add-on onto S6 Overlay - Rewrite add-on onto S6 Overlay
- Use default configuration location - Use default configuration location
- Add support for running in compatibility mode (SMB1/NT1) - Add support for running in compatibility mode (SMB1/NT1)
- Add dummy files to reduce number of errors/warnings in log output - Add dummy files to reduce number of errors/warnings in log output
## 9.1.0
- Allow IPv6 link-local hosts by default, consistent with IPv4 - Allow IPv6 link-local hosts by default, consistent with IPv4
## 9.0.0 ## 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 - New option `veto_files` to limit writing of specified files to the share
## 8.3.0 ## 8.3
- Fixes a bug in warning log message, causing start failure - Fixes a bug in warning log message, causing start failure
- Minor code cleanups - Minor code cleanups
## 8.2.0 ## 8.2
- Update from bash to bashio - Update from bash to bashio
## 8.1.0 ## 8.1
- Update Samba to version 4.8.8 - Update Samba to version 4.8.8
## 8.0.0 ## 8.0
- Fix access to /backup - 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

View File

@@ -1,17 +1,39 @@
# Home Assistant Add-on: Samba share # 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 ## Installation
Follow these steps to get the add-on installed on your system: Follow these steps to get the add-on installed on your system:
1. Navigate in your Home Assistant frontend to **Settings** -> **Add-ons** -> **Add-on store**. 1. Navigate in your Home Assistant frontend to **Supervisor** -> **Add-on Store**.
2. Find the "Samba share" add-on and click it. 2. Find the "Samba NAS share" add-on and click it.
3. Click on the "INSTALL" button. 3. Click on the "INSTALL" button.
## How to use ## How to use
1. In the configuration section, set a username and password. 1. In the configuration section, set a username and password.
You can specify any username and password; these are not related in any way to the login credentials you use to log in to Home Assistant or to log in to the computer with which you will use Samba share.
2. Review the enabled shares. Disable any you do not plan to use. Shares can be re-enabled later if needed. 2. Review the enabled shares. Disable any you do not plan to use. Shares can be re-enabled later if needed.
## Connection ## Connection
@@ -20,33 +42,26 @@ If you are on Windows you use `\\<IP_ADDRESS>\`, if you are on MacOS you use `sm
This addon exposes the following directories over smb (samba): This addon exposes the following directories over smb (samba):
Directory | Description | Directory | Description |
-- | -- | --------------- | ------------------------------------------------------------------------ |
`addons` | This is for your local add-ons. | `addons` | This is for your local add-ons. |
`addon_configs` | This is for the configuration files of your add-ons. | `backup` | This is for your snapshots. |
`backup` | This is for your backups. | `config` | This is for your Home Assistant configuration. |
`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. | `media` | This is for local media files. |
`share` | This is for your data that is shared between add-ons and Home Assistant. | `share` | This is for your data that is shared between add-ons and Home Assistant. |
`ssl` | This is for your SSL certificates. | `ssl` | This is for your SSL certificates. |
## Configuration ## Configuration
Add-on 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 ```yaml
workgroup: WORKGROUP workgroup: WORKGROUP
local_master: true local_master: true
username: homeassistant username: Hassio
password: YOUR_PASSWORD password: "<Your secret password>"
enabled_shares:
- addons
- addon_configs
- backup
- config
- media
- share
- ssl
allow_hosts: allow_hosts:
- 10.0.0.0/8 - 10.0.0.0/8
- 172.16.0.0/12 - 172.16.0.0/12
@@ -54,11 +69,37 @@ allow_hosts:
- 169.254.0.0/16 - 169.254.0.0/16
- fe80::/10 - fe80::/10
- fc00::/7 - fc00::/7
automount: true
moredisks:
- "<Partition's Label>"
- "id:<Partition uuid>"
mountoptions: "nosuid,relatime,noexec"
veto_files: veto_files:
- "._*" - "._*"
- ".DS_Store" - ".DS_Store"
- Thumbs.db - Thumbs.db
compatibility_mode: false 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) ### Option: `workgroup` (required)
@@ -77,21 +118,172 @@ The username you would like to use to authenticate with the Samba server.
The password that goes with the username configured for authentication. The password that goes with the username configured for authentication.
### Option: `enabled_shares` (required)
List of Samba shares that will be accessible. Any shares removed or commented out of the list will not be accessible.
### Option: `allow_hosts` (required) ### Option: `allow_hosts` (required)
List of hosts/networks allowed to access the shared folders. 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) ### Option: `veto_files` (optional)
List of files that are neither visible nor accessible. Useful to stop clients List of files that are neither visible nor accessible. Useful to stop clients
from littering the share with temporary hidden files from littering the share with temporary hidden files
(e.g., macOS `.DS_Store` or Windows `Thumbs.db` files) (e.g., macOS `.DS_Store` or Windows `Thumbs.db` files)
### Option: `compatibility_mode` ### 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 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 on the Samba add-on. This might solve issues with some clients that cannot
@@ -100,27 +292,120 @@ when you absolutely need it and understand the possible consequences.
Defaults to `false`. Defaults to `false`.
### Option: `apple_compatibility_mode` ### Option: `wsdd`
Enable Samba configurations to improve interoperability with Apple devices. Setting this option to `true` will enable the use of wsdd over internal samba system.
This can cause issues with file systems that do not support xattr such as exFAT.
Defaults to `true`. 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 ## Support
Got questions? ### 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>
You have several options to get them answered: ### Common problems
- The [Home Assistant Discord Chat Server][discord]. - **_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.
- The Home Assistant [Community Forum][forum].
- Join the [Reddit subreddit][reddit] in [/r/homeassistant][reddit] - **_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]. In case you've found a bug, please [open an issue on our GitHub][issue].
[discord]: https://discord.gg/c5DvZ4e [issue]: https://github.com/dianlight/hassio-addons/issues
[forum]: https://community.home-assistant.io
[issue]: https://github.com/home-assistant/addons/issues
[reddit]: https://reddit.com/r/homeassistant [reddit]: https://reddit.com/r/homeassistant
[repository]: https://github.com/hassio-addons/repository [repository]: https://github.com/dianlight/hassio-addons

View File

@@ -1,115 +1,150 @@
#============================#
# ALEXBELGIUM'S DOCKERFILE #
#============================#
# _.------.
# _.-` ('>.-`"""-.
# '.--'` _'` _ .--.)
# -' '-.-';` `
# ' - _.' ``'--.
# '---` .-'""`
# /`
#=== Home Assistant Addon ===#
#################
# 1 Build Image #
#################
ARG BUILD_FROM ARG BUILD_FROM
ARG BUILD_VERSION
FROM ${BUILD_FROM}
##################
# 2 Modify Image #
##################
# Set S6 wait time
ENV S6_CMD_WAIT_FOR_SERVICES=1 \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_SERVICES_GRACETIME=0
USER root
##################
# 3 Install apps #
##################
# Add rootfs
COPY rootfs/ /
# Uses /bin for compatibility purposes
# hadolint ignore=DL4005
RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \
if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi
# Modules
ARG MODULES="00-banner.sh 01-custom_script.sh 00-local_mounts.sh 00-smb_mounts.sh"
# Automatic modules download
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automodules.sh" "/ha_automodules.sh"
RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh
# Manual apps
ENV PACKAGES="bind-tools \
nginx"
# Automatic apps & bashio
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_autoapps.sh" "/ha_autoapps.sh"
RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.sh
################
# 4 Entrypoint #
################
# Add entrypoint
# ENV S6_STAGE2_HOOK=/ha_entrypoint.sh
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_entrypoint.sh" "/ha_entrypoint.sh"
# Entrypoint modifications
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_entrypoint_modif.sh" "/ha_entrypoint_modif.sh"
RUN chmod 777 /ha_entrypoint.sh /ha_entrypoint_modif.sh && /ha_entrypoint_modif.sh && rm /ha_entrypoint_modif.sh
# Standalone bashio command
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/bashio-standalone.sh" "/.bashio-standalone.sh"
RUN chmod 777 /.bashio-standalone.sh
RUN sed -i "s|/command/with-contenv|/usr/bin/env|g" "/ha_entrypoint.sh"
VOLUME [ "/data" ]
WORKDIR /
ENTRYPOINT [ "/usr/bin/env" ]
CMD [ "/ha_entrypoint.sh" ]
############
# 5 Labels #
############
ARG BUILD_ARCH
ARG BUILD_DATE ARG BUILD_DATE
ARG BUILD_DESCRIPTION ARG BUILD_DESCRIPTION
ARG BUILD_NAME ARG BUILD_NAME
ARG BUILD_REF ARG BUILD_REF
ARG BUILD_REPOSITORY ARG BUILD_REPOSITORY
ARG BUILD_VERSION ARG BUILD_VERSION
ENV BUILD_VERSION="${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 \ LABEL \
io.hass.name="${BUILD_NAME}" \ io.hass.name="${BUILD_NAME}" \
io.hass.description="${BUILD_DESCRIPTION}" \ io.hass.description="${BUILD_DESCRIPTION}" \
io.hass.arch="${BUILD_ARCH}" \ io.hass.arch="${BUILD_ARCH}" \
io.hass.type="addon" \ io.hass.type="addon" \
io.hass.version=${BUILD_VERSION} \ io.hass.version=${BUILD_VERSION} \
maintainer="alexbelgium (https://github.com/alexbelgium)" \ maintainer="Lucio Tarantino <@dianlight>" \
org.opencontainers.image.title="${BUILD_NAME}" \ org.opencontainers.image.title="${BUILD_NAME}" \
org.opencontainers.image.description="${BUILD_DESCRIPTION}" \ org.opencontainers.image.description="${BUILD_DESCRIPTION}" \
org.opencontainers.image.vendor="Home Assistant Add-ons" \ org.opencontainers.image.vendor="Home Assistant Dianlight Add-ons" \
org.opencontainers.image.authors="alexbelgium (https://github.com/alexbelgium)" \ org.opencontainers.image.authors="Lucio Tarantino <@dianlight>" \
org.opencontainers.image.licenses="MIT" \ org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.url="https://github.com/alexbelgium" \ org.opencontainers.image.url="https://github.com/dianlight/hassio-addons" \
org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \ 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.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \
org.opencontainers.image.created=${BUILD_DATE} \ org.opencontainers.image.created=${BUILD_DATE} \
org.opencontainers.image.revision=${BUILD_REF} \ org.opencontainers.image.revision=${BUILD_REF} \
org.opencontainers.image.version=${BUILD_VERSION} org.opencontainers.image.version=${BUILD_VERSION}
HEALTHCHECK \
CMD smbclient -L '\\localhost' -U '%' -m SMB3

View File

@@ -1,16 +1,57 @@
# Home Assistant Add-on: Samba share # Home Assistant Add-on: Samba NAS share
Share your configuration over the network using Windows file sharing. 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]
<!--
[![Stargazers repo roster for @dianlight/hassio-addons](https://raw.githubusercontent.com/dianlight/hassio-addons/master/.github/stars2.svg)](https://github.com/dianlight/hassio-addons/stargazers)
![downloads evolution](https://raw.githubusercontent.com/dianlight/hassio-addons/master/sambanas/stats.png)
-->
## 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
![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fanalytics.home-assistant.io%2Faddons.json&query=%24.1a32f091_sambanas.total&label=SambaNas%20Installations&link=https%3A%2F%2Faddonstats.poeschl.xyz%2F%23)
![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fanalytics.home-assistant.io%2Faddons.json&query=%24.c9a35110_sambanas.total&label=SambaNas%20β%20Installations&link=https%3A%2F%2Faddonstats.poeschl.xyz%2F%23)
## Help Me!
[![](https://img.shields.io/github/sponsors/dianlight?label=Sponsor&logo=GitHub)](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>
![Supports aarch64 Architecture][aarch64-shield] ![Supports amd64 Architecture][amd64-shield] ![Supports armhf Architecture][armhf-shield] ![Supports armv7 Architecture][armv7-shield] ![Supports i386 Architecture][i386-shield]
## About ## About
This Add-on allows you to enable file sharing across different operating systems over a network. 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. 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 [aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg
[amd64-shield]: https://img.shields.io/badge/amd64-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 [armhf-shield]: https://img.shields.io/badge/armhf-yes-green.svg
[armv7-shield]: https://img.shields.io/badge/armv7-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 [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
samba/apparmor.txt Normal file
View 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,
}

View File

@@ -1,10 +1,13 @@
--- ---
build_from: build_from:
aarch64: ghcr.io/home-assistant/aarch64-base:3.19 aarch64: ghcr.io/hassio-addons/base:17.2.5
amd64: ghcr.io/home-assistant/amd64-base:3.19 amd64: ghcr.io/hassio-addons/base:17.2.5
armhf: ghcr.io/home-assistant/armhf-base:3.19 armv7: ghcr.io/hassio-addons/base:17.2.5
armv7: ghcr.io/home-assistant/armv7-base:3.19 #codenotary:
i386: ghcr.io/home-assistant/i386-base:3.19 # signer: lucio.tarantino@gmail.com
codenotary: # base_image: codenotary@frenck.dev
signer: notary@home-assistant.io cosign:
base_image: notary@home-assistant.io # #base_identity: https://github.com/home-assistant/builder/.*
identity: https://github.com/dianlight/hassio-addons/.*
#args:
# HDDTEMP_VERSION: "0.3-beta15"

View File

@@ -1,140 +1,139 @@
--- ---
version: 12.5.2 name: Samba NAS
slug: samba version: 12.5.0-nas
name: Samba share slug: sambanas
description: Expose Home Assistant folders with SMB/CIFS description: Expose Home Assistant disc with SMB/CIFS
url: https://github.com/home-assistant/addons/tree/master/samba url: https://github.com/dianlight/hassio-addons/tree/master/sambanas
codenotary: notary@home-assistant.io codenotary: lucio.tarantino@gmail.com
arch: arch:
- armhf
- armv7 - armv7
- aarch64 - aarch64
- amd64 - amd64
- i386 startup: initialize
devices: boot: auto
- /dev/dri
- /dev/dri/card0
- /dev/dri/card1
- /dev/dri/renderD128
- /dev/vchiq
- /dev/video10
- /dev/video11
- /dev/video12
- /dev/video13
- /dev/video14
- /dev/video15
- /dev/video16
- /dev/ttyUSB0
- /dev/sda
- /dev/sdb
- /dev/sdc
- /dev/sdd
- /dev/sde
- /dev/sdf
- /dev/sdg
- /dev/nvme
- /dev/nvme0
- /dev/nvme0n1
- /dev/nvme0n1p1
- /dev/nvme0n1p2
- /dev/nvme0n1p3
- /dev/nvme1n1
- /dev/nvme1n1p1
- /dev/nvme1n1p2
- /dev/nvme1n1p3
- /dev/nvme2n1
- /dev/nvme2n1p1
- /dev/nvme2n1p2
- /dev/nvme2n3p3
- /dev/mmcblk
- /dev/fuse
- /dev/sda1
- /dev/sdb1
- /dev/sdc1
- /dev/sdd1
- /dev/sde1
- /dev/sdf1
- /dev/sdg1
- /dev/sda2
- /dev/sdb2
- /dev/sdc2
- /dev/sdd2
- /dev/sde2
- /dev/sdf2
- /dev/sdg2
- /dev/sda3
- /dev/sdb3
- /dev/sda4
- /dev/sdb4
- /dev/sda5
- /dev/sda6
- /dev/sda7
- /dev/sda8
- /dev/nvme0
- /dev/nvme1
- /dev/nvme2
- /dev/md0
- /dev/md1
- /dev/md2
- /dev/md3
environment:
PGID: "0"
PUID: "0"
privileged:
- SYS_ADMIN
- DAC_READ_SEARCH
hassio_api: true
host_network: true
image: homeassistant/{arch}-addon-samba
init: false init: false
hassio_api: true
hassio_role: admin
host_network: true
map: map:
- addons:rw
- all_addon_configs:rw
- backup:rw
- homeassistant_config:rw - homeassistant_config:rw
- media:rw - addon_config:rw
- share:rw
- ssl:rw - ssl:rw
- all_addon_configs:rw
- addons:rw
- share:rw
- backup:rw
- media:rw
options: options:
username: mezned
password: null
workgroup: WORKGROUP workgroup: WORKGROUP
username: homeassistant
local_master: true local_master: true
localdisks: sda8 allow_hosts:
enabled_shares: - 10.0.0.0/8
- addons - 172.16.0.0/12
- addon_configs - 192.168.0.0/16
- backup - 169.254.0.0/16
- config - fe80::/10
- media - fc00::/7
- share automount: true
- ssl moredisks: []
- sda8 mountoptions:
compatibility_mode: false - nosuid
apple_compatibility_mode: true - relatime
- noexec
available_disks_log: true
medialibrary:
enable: false
veto_files: veto_files:
- ._* - "._*"
- .DS_Store - ".DS_Store"
- Thumbs.db - Thumbs.db
- icon? - icon?
- .Trashes - ".Trashes"
allow_hosts: compatibility_mode: false
- 192.168.0.0/24 recyle_bin_enabled: false
- 192.168.10.0/24 wsdd2: false
- 100.0.0.0/8 wsdd: true
mqtt_nexgen_entities: false
autodiscovery: {}
other_users: []
acl: []
interfaces: []
schema: schema:
username: str
password: password
workgroup: str workgroup: str
local_master: bool local_master: bool
localdisks: str username: str
enabled_shares: password: password
- "match(^(?i:(addons|addon_configs|backup|config|media|share|ssl|sda8))$)" automount: bool?
compatibility_mode: bool moredisks:
apple_compatibility_mode: bool
veto_files:
- str - str
mountoptions:
- str
available_disks_log: bool?
medialibrary:
enable: bool?
ssh_private_key: password?
allow_hosts: allow_hosts:
- str - str
startup: services 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 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

View 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"

View 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

View File

@@ -0,0 +1 @@
longrun

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/cifs-supervisor-mount/finish

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/cifs-supervisor-mount/run

View 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"

View 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

View File

@@ -0,0 +1 @@
longrun

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-automount/finish

View 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."

View 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

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-automount/run

View 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

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-mqtt/run

View 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 "---------------------------------------------------"

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-samba/run

View 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

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-smartd/run

View File

@@ -1,166 +0,0 @@
#!/command/with-contenv bashio
# vim: ft=bash
# shellcheck shell=bash
# ==============================================================================
# Prepare the Samba service for running
# ==============================================================================
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
if ! bashio::supervisor.ping 2> /dev/null; then
echo "..."
exit 0
fi
bashio::log.notice "This script is used to mount local USB/SATA/SD/NVMe drives. Instructions here : https://github.com/alexbelgium/hassio-addons/wiki/Mounting-Local-Drives-in-Addons"
######################
# MOUNT LOCAL SHARES #
######################
# Mount local Share if configured
if bashio::config.has_value 'localdisks'; then
# Available devices
blkid | awk '{print substr($1, 0, length($1) - 1)}' | awk -F'/' '{print $NF}' > availabledisks
echo "NAME" >> availabledisks
## List available Disk with Labels and Id
bashio::log.blue "---------------------------------------------------"
bashio::log.info "Available Disks for mounting :"
lsblk -o name,label,size,fstype,ro | awk '$4 != "" { print $0 }' | grep -f availabledisks
bashio::log.blue "---------------------------------------------------"
rm availabledisks
# Show support fs https://github.com/dianlight/hassio-addons/blob/2e903184254617ac2484fe7c03a6e33e6987151c/sambanas/rootfs/etc/s6-overlay/s6-rc.d/init-automount/run#L106
fstypessupport=$(grep -v nodev < /proc/filesystems | awk '{$1=" "$1}1' | tr -d '\n\t')
bashio::log.green "Supported fs : ${fstypessupport}"
bashio::log.green "Inspired from : github.com/dianlight"
bashio::log.blue "---------------------------------------------------"
MOREDISKS=$(bashio::config 'localdisks')
echo "Local Disks mounting..."
# Separate comma separated values
# shellcheck disable=SC2086
for disk in ${MOREDISKS//,/ }; do
# Remove text until last slash
disk="${disk##*/}"
# Function to check what is the type of device
if [ -e /dev/"$disk" ]; then
echo "... $disk is a physical device"
devpath=/dev
elif [ -e /dev/disk/by-uuid/"$disk" ] || lsblk -o UUID | grep -q "$disk"; then
echo "... $disk is a device by UUID"
devpath=/dev/disk/by-uuid
elif [ -e /dev/disk/by-label/"$disk" ] || lsblk -o LABEL | grep -q "$disk"; then
echo "... $disk is a device by label"
devpath=/dev/disk/by-label
else
bashio::log.fatal "$disk does not match any known physical device, UUID, or label. "
continue
fi
# Creates dir
mkdir -p /mnt/"$disk"
if bashio::config.has_value 'PUID' && bashio::config.has_value 'PGID'; then
PUID="$(bashio::config 'PUID')"
PGID="$(bashio::config 'PGID')"
chown "$PUID:$PGID" /mnt/"$disk"
fi
# Check FS type and set relative options (thanks @https://github.com/dianlight/hassio-addons)
fstype=$(lsblk "$devpath"/"$disk" -no fstype)
options="nosuid,relatime,noexec"
type="auto"
# Check if supported
if [[ "${fstypessupport}" != *"${fstype}"* ]]; then
bashio::log.fatal : "${fstype} type for ${disk} is not supported"
break
fi
# Mount drive
bashio::log.info "Mounting ${disk} of type ${fstype}"
case "$fstype" in
exfat | vfat | msdos)
bashio::log.warning "${fstype} permissions and ACL don't works and this is an EXPERIMENTAL support"
options="${options},umask=000"
;;
ntfs)
bashio::log.warning "${fstype} is an EXPERIMENTAL support"
options="${options},umask=000"
type="ntfs"
;;
squashfs)
bashio::log.warning "${fstype} is an EXPERIMENTAL support"
options="loop"
type="squashfs"
;;
esac
# Legacy mounting : mount to share if still exists (avoid breaking changes)
dirpath="/mnt"
if [ -d /share/"$disk" ]; then dirpath="/share"; fi
# shellcheck disable=SC2015
mount -t $type "$devpath"/"$disk" "$dirpath"/"$disk" -o $options && bashio::log.info "Success! $disk mounted to /mnt/$disk" \
|| (
bashio::log.fatal "Unable to mount local drives! Please check the name."
rmdir /mnt/"$disk"
bashio::addon.stop
)
done
fi
declare password
declare username
declare -a interfaces=()
export HOSTNAME
# Check Login data
if ! bashio::config.has_value 'username' || ! bashio::config.has_value 'password'; then
bashio::exit.nok "Setting a username and password is required!"
fi
bashio::config.require "enabled_shares" "Samba is a tool for sharing folders. Starting it without sharing any folders defeats the purpose."
# Read hostname from API or setting default "hassio"
HOSTNAME=$(bashio::info.hostname)
if bashio::var.is_empty "${HOSTNAME}"; then
bashio::log.warning "Can't read hostname, using default."
HOSTNAME="hassio"
fi
bashio::log.info "Hostname: ${HOSTNAME}"
# Get supported interfaces
for interface in $(bashio::network.interfaces); do
interface_enabled=$(bashio::network.enabled "${interface}")
if bashio::var.true "${interface_enabled}"; then
interfaces+=("${interface}")
fi
done
if [ ${#interfaces[@]} -eq 0 ]; then
bashio::exit.nok 'No supported interfaces found to bind on.'
fi
bashio::log.info "Interfaces: $(printf '%s ' "${interfaces[@]}")"
# Generate Samba configuration.
jq ".interfaces = $(jq -c -n '$ARGS.positional' --args -- "${interfaces[@]}") |
.enabled_shares.[] |= ascii_downcase" /data/options.json \
| tempio \
-template /usr/share/tempio/smb.gtpl \
-out /etc/samba/smb.conf
# Init user
username=$(bashio::config 'username')
password=$(bashio::config 'password')
addgroup "${username}"
adduser -D -H -G "${username}" -s /bin/false "${username}"
(echo "$password"; echo "$password") \
| smbpasswd -a -s -c "/etc/samba/smb.conf" "${username}"

View File

@@ -1 +0,0 @@
oneshot

View File

@@ -1 +0,0 @@
/etc/s6-overlay/s6-rc.d/init-smbd/run

View 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 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"

View 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

View File

@@ -0,0 +1 @@
longrun

View 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"

View 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

View File

@@ -0,0 +1 @@
longrun

View File

@@ -1,27 +1,10 @@
#!/command/with-contenv bashio #!/usr/bin/with-contenv bashio
# vim: ft=bash
# shellcheck shell=bash
# ============================================================================== # ==============================================================================
# Take down the S6 supervision tree when nmbd fails # Take down the S6 supervision tree based on service exit code
# ============================================================================== # ==============================================================================
# shellcheck disable=SC2155 if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode) bashio::log.warning "nmbd crashed, halting add-on"
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
readonly service="nmbd"
bashio::log.info \
"Service ${service} exited with code ${exit_code_service}" \
"(by signal ${exit_code_signal})"
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
exec /run/s6/basedir/bin/halt exec /run/s6/basedir/bin/halt
fi fi
bashio::log.info "nmbd stopped"

View File

@@ -1,6 +1,4 @@
#!/command/with-contenv bashio #!/usr/bin/env bash
# vim: ft=bash
# shellcheck shell=bash
# ============================================================================== # ==============================================================================
# Start nmbd service # Start nmbd service
# ============================================================================== # ==============================================================================

View File

@@ -1,27 +1,12 @@
#!/command/with-contenv bashio #!/usr/bin/with-contenv bashio
# vim: ft=bash
# shellcheck shell=bash
# ============================================================================== # ==============================================================================
# Take down the S6 supervision tree when smbd fails # Take down the S6 supervision tree based on service exit code
# ============================================================================== # ==============================================================================
# shellcheck disable=SC2155 if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode) bashio::log.warning "smbd crashed, halting add-on"
readonly exit_code_service="${1}" bashio::log.info "Dump SMB configuration:"
readonly exit_code_signal="${2}" cat /etc/samba/smb.conf >&2
readonly service="smbd"
bashio::log.info \
"Service ${service} exited with code ${exit_code_service}" \
"(by signal ${exit_code_signal})"
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
exec /run/s6/basedir/bin/halt exec /run/s6/basedir/bin/halt
fi fi
bashio::log.info "smbd stopped"

View File

@@ -1,6 +1,4 @@
#!/command/with-contenv bashio #!/usr/bin/env bash
# vim: ft=bash
# shellcheck shell=bash
# ============================================================================== # ==============================================================================
# Start smbd service # Start smbd service
# ============================================================================== # ==============================================================================

View 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"

View 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

View File

@@ -0,0 +1 @@
longrun

View File

View 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())

View 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
samba/rootfs/usr/local/bin/poetry.lock generated Normal file
View 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"

View 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"

View File

@@ -1,8 +1,49 @@
[global] [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" }} netbios name = {{ env "HOSTNAME" }}
workgroup = {{ .workgroup }} workgroup = {{ .workgroup }}
server string = Samba Home Assistant server string = Samba NAS HomeAssistant config
local master = {{ .local_master | ternary "yes" "no" }} local master = {{ .local_master | ternary "yes" "no" }}
multicast dns register = {{ if or .wsdd .wsdd2 }}no{{ else }}yes{{ end }}
security = user security = user
ntlm auth = yes ntlm auth = yes
@@ -12,125 +53,103 @@
load printers = no load printers = no
disable spoolss = yes disable spoolss = yes
log level = 1 {{ $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 = yes bind interfaces only = {{ .bind_all_interfaces | default false | ternary "no" "yes" }}
interfaces = lo {{ .interfaces | join " " }} interfaces = 127.0.0.1 {{ .interfaces | join " " }} {{ .docker_interface | default " "}}
hosts allow = 127.0.0.1 {{ .allow_hosts | join " " }} hosts allow = 127.0.0.1 {{ .allow_hosts | join " " }} {{ .docker_net | default " " }}
{{ if .compatibility_mode }}
client min protocol = NT1
server min protocol = NT1
{{ end }}
mangled names = no mangled names = no
dos charset = CP850 dos charset = CP1253
unix charset = UTF-8 unix charset = UTF-8
{{ if .apple_compatibility_mode }} {{ define "SHT" }}
vfs objects = catia fruit streams_xattr {{- $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 }} {{ end }}
{{ if (has "config" .enabled_shares) }}
[config]
browseable = yes
writeable = yes
path = /homeassistant
valid users = {{ .username }}
force user = root force user = root
force group = root force group = root
veto files = /{{ .veto_files | join "/" }}/ veto files = /{{ .veto_files | join "/" }}/
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} 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 }} {{ end }}
{{ if (has "addons" .enabled_shares) }} # 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 }}
[addons] {{- if and .timemachine (has $dinfo.fs $unsupported | not ) }}
browseable = yes vfs objects = catia fruit streams_xattr{{ if .recyle_bin_enabled }} recycle{{ end }}
writeable = yes
path = /addons
valid users = {{ .username }} # Time Machine Settings Ref: https://github.com/markthomas93/samba.apple.templates
force user = root fruit:time machine = yes
force group = root #fruit:time machine max size = SIZE [K|M|G|T|P]
veto files = /{{ .veto_files | join "/" }}/ fruit:metadata = stream
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} {{ end }}
{{- if has $dinfo.fs $unsupported }}
vfs objects = catia{{ if .recyle_bin_enabled }} recycle{{ end }}
{{ end }} {{ end }}
{{ if (has "addon_configs" .enabled_shares) }}
[addon_configs]
browseable = yes
writeable = yes
path = /addon_configs
valid users = {{ .username }}
force user = root
force group = root
veto files = /{{ .veto_files | join "/" }}/
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }}
{{ end }} {{ end }}
{{ if (has "ssl" .enabled_shares) }} {{- $dfdisk := list "config" "addons" "ssl" "share" "backup" "media" "addon_configs" }}
[ssl] {{- $disks := concat $dfdisk (compact .moredisks|default list) -}}
browseable = yes {{- $root := . -}}
writeable = yes {{- range $disk := $disks -}}
path = /ssl {{- $acld := false -}}
{{- range $dd := $root.acl -}}
valid users = {{ .username }} {{- $ndisk := $disk | regexFind "[A-Za-z0-9_]+$" -}}
force user = root {{- if eq ($dd.share|upper) ($ndisk|upper) -}}
force group = root {{- $def := deepCopy $dd }}
veto files = /{{ .veto_files | join "/" }}/ {{- $acld = true -}}
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} {{- if not $dd.disabled -}}
{{ end }} {{- $_ := set $dd "share" $disk -}}
{{- if has $disk $dfdisk -}}
{{ if (has "share" .enabled_shares) }} {{- $_ := set $def "timemachine" false -}}
[share] {{- $_ := set $def "usage" "" -}}
browseable = yes {{- else -}}
writeable = yes {{- $_ := set $def "timemachine" true -}}
path = /share {{- $_ := set $def "usage" "media" -}}
{{- end }}
valid users = {{ .username }} {{- template "SHT" deepCopy $root | mergeOverwrite $def $dd -}}
force user = root {{- end -}}
force group = root {{- end -}}
veto files = /{{ .veto_files | join "/" }}/ {{- end -}}
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} {{- if not $acld -}}
{{ end }} {{- $dd := dict "share" $disk "timemachine" true -}}
{{- $_ := set $dd "usage" "media" -}}
{{ if (has "backup" .enabled_shares) }} {{- if has $disk $dfdisk -}}
[backup] {{- $_ := set $dd "timemachine" false -}}
browseable = yes {{- $_ := set $dd "usage" "" -}}
writeable = yes {{- end }}
path = /backup {{- template "SHT" (deepCopy $root | mergeOverwrite $dd) -}}
{{- end -}}
valid users = {{ .username }} {{- end -}}
force user = root
force group = root
veto files = /{{ .veto_files | join "/" }}/
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }}
{{ end }}
{{ if (has "media" .enabled_shares) }}
[media]
browseable = yes
writeable = yes
path = /media
valid users = {{ .username }}
force user = root
force group = root
veto files = /{{ .veto_files | join "/" }}/
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }}
{{ end }}
{{ if (has "sda8" .enabled_shares) }}
[sda8]
browseable = yes
writeable = yes
path = /mnt/sda8
valid users = {{ .username }}
force user = root
force group = root
veto files = /{{ .veto_files | join "/" }}/
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }}
{{ end }}

5
samba/test/buildLocal.sh Normal file
View 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
samba/test/options.json Normal file
View 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
samba/test/runLocal.sh Normal file
View 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

View File

@@ -17,7 +17,7 @@ configuration:
enabled_shares: enabled_shares:
name: >- name: >-
Enabled Shares - allowed values are: Enabled Shares - allowed values are:
addons, addon_configs, backup, config, media, share, /mnt/old_data or ssl. addons, addon_configs, backup, config, media, share, or ssl.
description: >- description: >-
List of file shares to make available. List of file shares to make available.
Adding a share requires typing its name to add it. Adding a share requires typing its name to add it.
@@ -27,15 +27,71 @@ configuration:
name: Enable Compatibility Mode name: Enable Compatibility Mode
description: >- description: >-
Enable this to use old legacy Samba protocols on the Samba add-on. Enable this to use old legacy Samba protocols on the Samba add-on.
apple_compatibility_mode:
name: Enable Compatibility Settings for Apple Devices
description: >-
Enable Samba configurations to improve interoperability with Apple
devices. May cause issues with file systems that do not support xattr
such as exFAT.
veto_files: veto_files:
name: Veto Files name: Veto Files
description: List of files that are neither visible nor accessible. description: List of files that are neither visible nor accessible.
allow_hosts: allow_hosts:
name: Allowed Hosts name: Allowed Hosts
description: List of hosts/networks allowed to access the shared folders. 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