New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds folder_watcher component #12918

Merged
merged 63 commits into from Mar 30, 2018

Conversation

@robmarkcole
Contributor

robmarkcole commented Mar 5, 2018

Description:

Replaces #12912 as becomes a standalone component. This component adds Watchdog file system monitoring, with events published for changes to files within the filesystem.

Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.github.io#<4885>

Example entry for configuration.yaml (if applicable):

folder_watcher:
  - folder: /Users/robincole/.homeassistant/images
    patterns:
      - '*.jpg'
  - folder: /Users/robincole/.homeassistant/www
    patterns:
      - '*.jpg'

Checklist:

  • The code change is tested and works locally.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • Local tests with tox run successfully. Your PR cannot be merged unless tests pass
  • New dependencies have been added to the REQUIREMENTS variable ([example][ex-requir]).
  • New dependencies are only imported inside functions that use them ([example][ex-import]).
  • New dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
  • New files were added to .coveragerc.
from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv
#DEPENDENCIES = ['watchdog']

This comment has been minimized.

@houndci-bot

houndci-bot Mar 5, 2018

block comment should start with '# '

This comment has been minimized.

@balloob

balloob Mar 5, 2018

Member

Remove this.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

ok

DOMAIN = "watchdog_file_watcher"
EVENT_TYPE = "event_type"
SRC_PATH = "src_path"
PATTERNS = ["*.txt", "*.py", "*.md", "*.jpg", "*.png"]

This comment has been minimized.

@OttoWinter

OttoWinter Mar 5, 2018

Contributor

I don't think we should restrict file patterns like this, if at all.

This comment has been minimized.

@dgomes

dgomes Mar 5, 2018

Member

Make it configurable

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

Agreed

_LOGGER.error("folder %s is not valid or allowed", path)
else:
Watcher(path, hass)
return True

This comment has been minimized.

@OttoWinter

OttoWinter Mar 5, 2018

Contributor

I think we should return False in the _LOGGER.error("folder %s is not valid or allowed", path) block.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

ok

def async_setup(hass, config):
"""Set up the folder watcher."""
conf = config.get(DOMAIN)
path = conf.get(CONF_PATH)

This comment has been minimized.

@OttoWinter

OttoWinter Mar 5, 2018

Contributor

Use index syntax for required keys:

path = conf[CONF_PATH]

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

ok

self.hass.bus.fire(
DOMAIN, {
EVENT_TYPE: event.event_type,
SRC_PATH: event.src_path})

This comment has been minimized.

@OttoWinter

OttoWinter Mar 5, 2018

Contributor

Just a question, but should we use absolute paths for events or paths relative to the directory we specified.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

Well my use case is having an automation run on the file identified by the path, so if we use relative paths is would then require the automation to append the rest of the path which is a hassle. I propose just splitting out the file_name and firing that too?

if not hass.config.is_allowed_path(path):
_LOGGER.error("folder %s is not valid or allowed", path)
else:
Watcher(path, hass)

This comment has been minimized.

@OttoWinter

OttoWinter Mar 5, 2018

Contributor

I'm not entirely sure how entities are added for components, but when does this entity get added to hass?

Also, why is this a component and not a sensor platform?

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

Im not sure about this too, but it appears to work..

"""Process the Watchdog event."""
self.hass.bus.fire(
DOMAIN, {
EVENT_TYPE: event.event_type,

This comment has been minimized.

@OttoWinter

OttoWinter Mar 5, 2018

Contributor

I think you need to specify the event_type as a positional arg/kwarg. fire signature:

def fire(self, event_type: str, event_data=None, origin=EventOrigin.local):

Also, I don't think we should be directly using the event_types from watchdog, we should at least translate them to EVENT_* constants even if they end up being the same string. I mean it probably won't happen, but what if watchdog changes their event types.

This comment has been minimized.

@balloob

balloob Mar 5, 2018

Member

Well Otto, that's where Rob is one step ahead of you 😉 He is actually firing watchdog_file_watcher events. The subtype is the watchdog type.

I am not sure if we would want to have 1 event with sub event types or have each watchdog event type be it's own event in Home Assistant. I kinda like how it is now.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

I want automations to trigger on particular event types and not make this too complicated, I also like how it is now

return True
class Watcher(Entity):

This comment has been minimized.

@OttoWinter

OttoWinter Mar 5, 2018

Contributor

I think you can move the event handler into the entity:

class Watcher(Entity, PatternMatchingEventHandler):

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

I will have a go

MyHandler(hass),
path,
recursive=True)
self._observer.start()

This comment has been minimized.

@OttoWinter

OttoWinter Mar 5, 2018

Contributor

I think we should only start observing once we're added_to_hass. Doing work or I/O in the constructor is a really bad idea 😉

This comment has been minimized.

@balloob

balloob Mar 5, 2018

Member

There is no added_to_hass as it's not an entity. Instead, we should listen to the HOMEASSISTANT_START event and start then.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

ok

@@ -0,0 +1,75 @@
"""
Component for monitoring activity on a folder.

This comment has been minimized.

@balloob

balloob Mar 5, 2018

Member

The name of this component is weird.

  • it's watching a folder
  • but it's called watchdog_file_watcher

Watchdog is the requirement that is used. Probably just folder_watcher would be an ok name ?

This comment has been minimized.

@balloob

balloob Mar 5, 2018

Member

Also don't forget to specify a REQUIREMENTS constant with watchdog in it

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

Yes I'm happy with folder_watcher

EVENT_TYPE: event.event_type,
SRC_PATH: event.src_path})
def on_modified(self, event):

This comment has been minimized.

@balloob

balloob Mar 5, 2018

Member

What happened to the on_any_event handler ?

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

I guess its replaced with process() for PatternMatchingEventHandler, will check

@asyncio.coroutine
def async_setup(hass, config):

This comment has been minimized.

@balloob

balloob Mar 5, 2018

Member

This should not be async. You're doing a shit ton of I/O which is not allowed inside the event loop.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

ok

CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_PATH): cv.isdir})

This comment has been minimized.

@balloob

balloob Mar 5, 2018

Member

This only allows 1 path to be specified. I think that we should take in a list of paths. vol.All(cv.ensure_list, [cv.isdir])

This comment has been minimized.

@robmarkcole

robmarkcole Mar 6, 2018

Contributor

Agreed. I propose to take a list of paths, with recursive and patterns as optional on each path.

@robmarkcole robmarkcole changed the title from WIP - Adds watchdog_file_watcher component to WIP - Adds folder_watcher component Mar 6, 2018

from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv
#DEPENDENCIES = ['watchdog']

This comment has been minimized.

@houndci-bot

houndci-bot Mar 6, 2018

block comment should start with '# '

@robmarkcole

This comment has been minimized.

Contributor

robmarkcole commented Mar 6, 2018

Thanks for your feedback @balloob and @OttoWinter I have time to work on this at the weekend.
Cheers

MyHandler(hass),
path,
recursive=DEFAULT_IS_RECURSIVE)
self._observer.start()

This comment has been minimized.

@robmarkcole

robmarkcole Mar 7, 2018

Contributor

How to listen for HOMEASSISTANT_START - I have to apply a decorator to self._observer.start()?

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

(My GitHub client is not working correctly, repost)

I didn't really understand @balloob's comment from before, since from what I know this is an entity. Here's how I would have done it:

class FolderWatcher(Entity, FileSystemEventHandler):
    def __init__(self, path):
        self._observer = Observer()
        self._path = path

    async def async_added_to_hass(self):
        self.hass.async_add_job(self.start_watching)

    async def async_will_remove_from_hass(self):
        self.hass.async_add_job(self.stop_watching)

    def start_watching(self):
        self._observer.schedule(self, self._path, recursive=True)
        self._observer.start()

    def stop_watching(self):
        self._observer.stop()

    def process(self, event):
        on_any_event(self.hass, event)

    def on_modified(self, event):
        self.process(event)

    def on_moved(self, event):
        self.process(event)

    def on_created(self, event):
        self.process(event)

    def on_deleted(self, event):
        self.process(event)

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

@OttoWinter tried that but async_added_to_hass() is never called

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

I also receive another error using FolderWatcher(Entity, FileSystemEventHandler): that I don't understand:

2018-03-08 06:36:30 ERROR (MainThread) [homeassistant.setup] Error during setup of component folder_watcher
Traceback (most recent call last):
  File "/Users/robincole/Documents/Github/home-assistant/homeassistant/setup.py", line 145, in _async_setup_component
    component.setup, hass, processed_config)
  File "/anaconda3/lib/python3.6/asyncio/futures.py", line 332, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/anaconda3/lib/python3.6/asyncio/tasks.py", line 250, in _wakeup
    future.result()
  File "/anaconda3/lib/python3.6/asyncio/futures.py", line 245, in result
    raise self._exception
  File "/anaconda3/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/Users/robincole/.homeassistant/custom_components/folder_watcher.py", line 38, in setup
    FolderWatcher(path)
  File "/Users/robincole/.homeassistant/custom_components/folder_watcher.py", line 57, in __init__
    self._observer.schedule(self, self._path, recursive=True)
  File "/Users/robincole/Documents/Github/home-assistant/lib/python3.6/site-packages/watchdog/observers/fsevents.py", line 172, in schedule
    return BaseObserver.schedule(self, event_handler, path, recursive)
  File "/Users/robincole/Documents/Github/home-assistant/lib/python3.6/site-packages/watchdog/observers/api.py", line 284, in schedule
    self._add_handler_for_watch(event_handler, watch)
  File "/Users/robincole/Documents/Github/home-assistant/lib/python3.6/site-packages/watchdog/observers/api.py", line 243, in _add_handler_for_watch
    self._handlers[watch].add(event_handler)
TypeError: unhashable type: 'FolderWatcher'

This comment has been minimized.

@OttoWinter

OttoWinter Mar 8, 2018

Contributor

Are you using the setup_platform() code? I'm pretty sure async_added_to_hass would be called for entities of a platform component and quite a few integrations depend on it.

def setup_platform(hass, config, add_devices, discovery_info=None):
    # ...
    add_devices([FolderWatcher(...)])

That should call the async_added_to_hass callback.

This comment has been minimized.

@OttoWinter

OttoWinter Mar 8, 2018

Contributor

Oh the unhashable type is an issue. If I understand correctly watchdog tries to put the entity in a set. And to be added to a set an object must be hashable (implementing the hash function). Entities however are apparently unhashable, so using class FolderWatcher(Entity, FileSystemEventHandler): won't work.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

@OttoWinter I'm using setup(), also I am confused now why you recommend setup_platform() as this is a component, not a sensor, perhaps I'm missing something?

This comment has been minimized.

@OttoWinter

OttoWinter Mar 8, 2018

Contributor

Ohhhh! Sorry I thought this would be a replacement for the folder sensor, just with the added benefit of firing events. However, you correctly said "Replaces #12912 as becomes a standalone component." at the top of your PR.

This comment has been minimized.

@balloob

balloob Mar 9, 2018

Member

If you want to learn how to use the start event, check the code… git grep EVENT_HOMEASSISTANT_START

DOMAIN: vol.Schema({
vol.Required(CONF_FOLDERS):
vol.All(cv.ensure_list, [cv.isdir]),
})

This comment has been minimized.

@robmarkcole

robmarkcole Mar 7, 2018

Contributor

Could add config for file types to watch/not_watch - should this be applied to all folders or folder by folder? I'm not a fan of overly complex config

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

I think if this should be added, then as a glob-style filter, though I don't think the it's really something we should do anyway.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

@OttoWinter what is your thinking behind not adding?

def on_any_event(hass, event):
if not event.is_directory:

This comment has been minimized.

@robmarkcole

robmarkcole Mar 7, 2018

Contributor

Added otherwise you get a folder modified event every time a file is changed, which is overkill in my opinion but perhaps people want this?

self._observer.schedule(
MyHandler(hass),
path,
recursive=DEFAULT_IS_RECURSIVE)

This comment has been minimized.

@robmarkcole

robmarkcole Mar 7, 2018

Contributor

Make IS_RECURSIVE configurable?

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

I personally don't think so, but it could be also done using the glob approach described before.

'folder': event_folder})
class MyHandler(FileSystemEventHandler):

This comment has been minimized.

@robmarkcole

robmarkcole Mar 7, 2018

Contributor

Probably EventHandler is a better name - but don't want to confuse with Home-assistant events..? Alternatively as per @OttoWinter previous comments I could merge this class with the Watcher class, although the current implementation makes comparison with the Watchdog examples very clear

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

Changed to WatcherHandler

DOMAIN: vol.Schema({
vol.Required(CONF_FOLDERS):
vol.All(cv.ensure_list, [cv.isdir]),
})

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

I think if this should be added, then as a glob-style filter, though I don't think the it's really something we should do anyway.

}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

Now that you've converted this into a platform, you also need to change this to a setup_platform function. See this for an example:

def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the folder sensor."""
path = config.get(CONF_FOLDER_PATHS)
if not hass.config.is_allowed_path(path):
_LOGGER.error("folder %s is not valid or allowed", path)
else:
folder = Folder(path, config.get(CONF_FILTER))
add_devices([folder], True)

This comment has been minimized.

@robmarkcole

robmarkcole Mar 7, 2018

Contributor

Oh yes, I wrote that :)

_LOGGER = logging.getLogger(__name__)
CONF_FOLDERS = 'folders'
DOMAIN = "folder_watcher"

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

Platforms don't have domains.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

Is component

from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['watchdog']

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

I think we're required to pin the requirements versions. For example

REQUIREMENTS = ['watchdog==0.8.3']

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

ok

import os
import logging
import voluptuous as vol
from watchdog.observers import Observer

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

Then also move these imports into local imports. For example

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

@OttoWinter If I do this:
image

I get the error:

  File "/Users/robincole/.homeassistant/custom_components/folder_watcher.py", line 63, in <module>
    class WatcherHandler(FileSystemEventHandler):
NameError: name 'FileSystemEventHandler' is not defined
EVENT_TYPE = "event_type"
IS_DIRECTORY = "is_directory"
CONFIG_SCHEMA = vol.Schema({

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

As a platform, you now need to specify a PLATFORM_SCHEMA instead:

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_FOLDER_PATHS): cv.isdir,
vol.Optional(CONF_FILTER, default=DEFAULT_FILTER): cv.string,
})

self._observer.schedule(
MyHandler(hass),
path,
recursive=DEFAULT_IS_RECURSIVE)

This comment has been minimized.

@OttoWinter

OttoWinter Mar 7, 2018

Contributor

I personally don't think so, but it could be also done using the glob approach described before.

import os
import logging
import voluptuous as vol
from watchdog.events import FileSystemEventHandler

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

I'm not sure where to import

if not event.is_directory:
file_name = os.path.split(event.src_path)[1]
if not file_name.startswith('.'): # Avoid hidden files.
if fnmatch.fnmatch(file_name, file_filter): # Apply filter.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

In my ignorance of fnmatch I am unsure how to apply multiple filters, e.g. *.txt *.jpg

recursive=True)
self._observer.start()
def stop_watching(self):

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

This is currently never called

"""On Watcher event, fire HA event."""
if not event.is_directory:
file_name = os.path.split(event.src_path)[1]
if not file_name.startswith('.'): # Avoid hidden files.

This comment has been minimized.

@robmarkcole

robmarkcole Mar 8, 2018

Contributor

I'm now filtering out hidden files, which I presume people prefer?

@OttoWinter

This comment has been minimized.

Contributor

OttoWinter commented Mar 8, 2018

Sorry about those previous comments, a few of them do not apply since this a component and not a platform. Here's a few thoughts I have on this:

Use cases

I think we should think about use cases for this component for our other decisions.

  • Use case #.1: Reloading/Restarting Home Assistant automatically on configuration file changes.
    • Would need some sort of filtering files, since we shouldn't restart Home Assistant on entity_registry.yaml updates.
  • Use case #.2: File system events from other applications (for example backups).
    • Will probably never work with hass.io/docker, since the file systems are intentionally separated for those.
  • I'm sure there are other uses cases for this, feel free to comment them.

File filtering

You implemented some file filtering options, I understand the need for them, but we should think about how they should be done.

  • Option #.1: Don't filter files. This was my initial idea to keep the component as simple as possible, but use cases #.1 & #.2 heavily depend on filtering files.
    • I think if we do not allow manual filtering, we should definitely not filter some files by default, for example hidden files (.*). At some point the component just seems to restrictive.
  • Option #.2: File filtering inside FolderWatcher. Things to consider:
    • The configuration would be cleaner. Having the filters right next to the folder_watcher (or whatever it will be called) is nice.
    • What if I want a folder watcher A for /config with filtering out /config/foo.txt, but another folder watcher also for /config, but without any filters. Because we publish to the event bus globally, we can't distinguish between the events of the two.
  • Option #.3: File filtering in automations.
    • Filters would sit far away from the folder_watcher: config. Not very nice.
    • Not sure how this could be done at all. Maybe with a new condition: type, but adding yet
      another condition type is not too nice.
    • Allows automations to watch for very specific file events.

File filters we could use:

  • globbing: **/*.py
    • Can't be used very well with multiple filters. For example filtering out entity_registry.yaml, but not configuration.yaml.
    • watchdog has something like this already: PatternMatchingEventHandler
  • .gitignore style
    • Well known and easy to use. Still allows for complicated filters.
  • regex
    • Quite well known
    • Can be difficult to use
    • Has "too many" options (also not sure security-wise)
    • Usually not used for paths.

Platform vs. Component

At first I thought this was going to be a rewrite of the folder sensor. Honestly, I think it would kind of make for sense there. Maybe there already was a discussion on this that I missed/can't remember. Some thoughts:

  • With a folder sensor and folder component, I think we would only confuse users. They seem quite similar functionality-wise to me, only with this PR having the events.
  • On the other side, I don't really expect sensors to fire events...

watchdog import issues

We can't do global imports because then every user would need to download watchdog even if they're not using the folder watcher. Your case is however a bit tricky, since you need to create a class that extends an imported abstract class.

This could be a way to fix it; it's not very nice though and there might very well be better options.

def create_event_handler(file_filter, hass):
    from watchdog.events import FileSystemEventHandler

    class FolderWatcherEventHandler(FileSystemEventHandler):
        def __init__(self, file_filter, hass):
            super().__init__(FolderWatcherEventHandler, self).__init__()
            self._file_filter = file_filter
            self.hass = hass

        def process(self, event):
            on_any_event(self.hass, self._file_filter, event)

        def on_modified(self, event):
            self.process(event)

        def on_moved(self, event):
            self.process(event)

        def on_created(self, event):
            self.process(event)

        def on_deleted(self, event):
            self.process(event)

    return FolderWatcherEventHandler(file_filter, hass)
@robmarkcole

This comment has been minimized.

Contributor

robmarkcole commented Mar 8, 2018

@OttoWinter thanks for your detailed comments.

Use case

Mine is to monitor a folder where a motion activate camera is saving time-stamped files. I will use an automation to watch for new images then send them image processing. The same principle applies to services that save .txt or other files. If people want to watch for individual files, they can specify the file_name as a filter in their automation.

File filtering

I agree this is necessary. I've implemented the PatternMatchingEventHandler class which uses glob.

Platform vs. Component

There was indeed an earlier conversation about this. A sensor alone might miss files being added if two were added at the same time, therefore events are necessary. There is so much overlap with the folder sensor I am beginning to think this PR should be integrated to it. This would improve the folder sensor as the number of files it displays can be updated immediately, rather than having a scan_interval of 30 seconds. The folder sensor could then have an attribute for the last X events, but the docs make clear that people should use events for automations. Is that too complicated? @balloob @dgomes

Re imports, @OttoWinter your suggestion works :-)

robmarkcole added some commits Mar 24, 2018

@robmarkcole

This comment has been minimized.

Contributor

robmarkcole commented Mar 24, 2018

In my tests if I have:

self.assertTrue(self.hass.bus.fire.called)

python 3.5.3 test passes but python 3.6 fails, but if I have:

self.hass.bus.fire.assert_called()

python 3.6 test passes but python 3.5.3 fails.
Please advise.

UPDATE - this passes 3.5.3 and 3.6

assert self.hass.bus.fire.called

robmarkcole added some commits Mar 24, 2018

Merge remote-tracking branch 'origin/patch-5' into patch-5
# Conflicts:
#	tests/components/test_folder_watcher.py
@robmarkcole

This comment has been minimized.

Contributor

robmarkcole commented Mar 24, 2018

Travis is seriously driving me mad :-0

The only test now failing states requirements_test_all.txt is not up to date Please run script/gen_requirements_all.py but if I run that my reference to watchdog is removed from requirements_test_all.txt and then the other tests fail because they cannot import watchdog..

robmarkcole added some commits Mar 25, 2018

@robmarkcole

This comment has been minimized.

Contributor

robmarkcole commented Mar 27, 2018

Request final review @OttoWinter @balloob

@balloob

This comment has been minimized.

Member

balloob commented Mar 30, 2018

🎉

@balloob balloob merged commit df78eec into home-assistant:dev Mar 30, 2018

5 checks passed

WIP ready for review
Details
cla-bot Everyone involved has signed the CLA
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls Coverage decreased (-0.1%) to 93.932%
Details
hound No violations found. Woof!

@robmarkcole robmarkcole deleted the robmarkcole:patch-5 branch Mar 30, 2018

@balloob balloob referenced this pull request Apr 13, 2018

Merged

0.67.0 #13856

@bachulator

This comment has been minimized.

bachulator commented Apr 18, 2018

Wondering is it easy enough to add network share (NFS, SAMBA, FTP etc) monitoring directly from config file. Would be super handy for prople using restricted environment like Hassio.

@robmarkcole

This comment has been minimized.

Contributor

robmarkcole commented Apr 18, 2018

@bachulator I don’t think that’s covered by Watchdog

@bachulator

This comment has been minimized.

bachulator commented Apr 18, 2018

Ok thanks, sad though, from FS perspective is rather close functionality.

@home-assistant home-assistant locked and limited conversation to collaborators Jul 26, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.