Example #1
0
        public async Task ACustomEventShouldUsingSelectorUsingDataNotExisstFuncNotCall()
        {
            // ARRANGE
            var     hcMock     = HassClientMock.DefaultMock;
            var     daemonHost = new NetDaemonHost(hcMock.Object, new Mock <IDataRepository>().Object);
            dynamic dynObject  = new ExpandoObject();

            dynObject.Test = "Hello World!";

            hcMock.AddCustomEvent("CUSTOM_EVENT", dynObject);

            var    cancelSource = hcMock.GetSourceWithTimeout();
            var    isCalled     = false;
            string?message      = "";

            daemonHost
            .Events(n => n.EventId == "CUSTOM_EVENT" && n?.Data?.NotExist == "Hello Test!")
            .Call((ev, data) =>
            {
                isCalled = true;
                message  = data?.Test;
                return(Task.CompletedTask);
            }).Execute();

            try
            {
                await daemonHost.Run("host", 8123, false, "token", cancelSource.Token).ConfigureAwait(false);
            }
            catch (TaskCanceledException)
            {
                // Expected behaviour
            }

            Assert.False(isCalled);
        }
Example #2
0
        public CoreDaemonHostTestBase() : base()
        {
            DefaultDaemonApp = new BaseTestApp
            {
                Id        = "app_id",
                IsEnabled = true
            };

            DefaultDaemonHost.AddRunningApp(DefaultDaemonApp);

            DefaultDaemonRxApp = new BaseTestRxApp
            {
                Id        = "app_rx_id",
                IsEnabled = true
            };
            DefaultDaemonHost.AddRunningApp(DefaultDaemonRxApp);

            DefaultMockedRxApp = new Mock <NetDaemonRxApp>()
            {
                CallBase = true
            };
            DefaultMockedRxApp.Object.Id        = "app_rx_mock_id";
            DefaultMockedRxApp.Object.IsEnabled = true;
            DefaultMockedRxApp.Setup(n => n.CreateObservableIntervall(It.IsAny <TimeSpan>(), It.IsAny <Action>())).Returns(new Mock <IDisposable>().Object);

            DefaultDaemonHost.AddRunningApp(DefaultMockedRxApp.Object);

            var notConnectedHassClientFactoryMock = new HassClientFactoryMock(HassClientMock.MockConnectFalse);

            _notConnectedDaemonHost = new NetDaemonHost(notConnectedHassClientFactoryMock.Object, DefaultDataRepositoryMock.Object, LoggerMock.LoggerFactory);

            SetupFakeData();
        }
Example #3
0
        private async Task GenerateEntities(NetDaemonHost daemonHost, string sourceFolder)
        {
            if (!_netDaemonSettings.GenerateEntities.GetValueOrDefault())
            {
                return;
            }

            if (_entitiesGenerated)
            {
                return;
            }

            _logger.LogTrace("Generating entities from Home Assistant instance ..");

            _entitiesGenerated = true;

            var services = await daemonHost.GetAllServices().ConfigureAwait(false);

            var sourceRx = CodeGenerator.GenerateCodeRx(
                "Netdaemon.Generated.Reactive",
                daemonHost.State.Select(n => n.EntityId).Distinct(),
                services
                );

            await File.WriteAllTextAsync(Path.Combine(sourceFolder !, "_EntityExtensionsRx.cs.gen"), sourceRx).ConfigureAwait(false);
        }
Example #4
0
        public void RunNullReferenceToHassClientShouldThrowException()
        {
            // ARRANGE

            // ACT and ASSERT
            Assert.Throws <ArgumentNullException>(() =>
                                                  { var DefaultDaemonHost = new NetDaemonHost(null, null); });
        }
Example #5
0
 internal DaemonHostTestaBase()
 {
     _loggerMock                = new LoggerMock();
     _defaultHassClientMock     = HassClientMock.DefaultMock;
     _defaultDataRepositoryMock = new Mock <IDataRepository>();
     _defaultDaemonHost         = new NetDaemonHost(_defaultHassClientMock.Object, _defaultDataRepositoryMock.Object, _loggerMock.LoggerFactory);
     _notConnectedDaemonHost    = new NetDaemonHost(HassClientMock.MockConnectFalse.Object, _defaultDataRepositoryMock.Object, _loggerMock.LoggerFactory);
 }
Example #6
0
        public void ACustomEventNullValueCallThrowsNullReferenceException()
        {
            // ARRANGE
            var hcMock     = HassClientMock.DefaultMock;
            var daemonHost = new NetDaemonHost(hcMock.Object, new Mock <IDataRepository>().Object);

            var cancelSource = hcMock.GetSourceWithTimeout();

            Assert.Throws <NullReferenceException>(() => daemonHost
                                                   .Event("CUSTOM_EVENT")
                                                   .Call(null).Execute());
        }
Example #7
0
        /// <inheritdoc/>
        public Task GenerateEntitiesAsync(NetDaemonHost daemonHost, string sourceFolder)
        {
            if (daemonHost == null)
            {
                throw new ArgumentNullException(nameof(daemonHost));
            }
            if (sourceFolder == null)
            {
                throw new ArgumentNullException(nameof(sourceFolder));
            }

            return(GenerateEntitiesAsyncInternal(daemonHost, sourceFolder));
        }
Example #8
0
        private async Task WaitForDaemonToConnect(NetDaemonHost daemonHost, CancellationToken stoppingToken)
        {
            var nrOfTimesCheckForConnectedState = 0;

            while (!daemonHost.Connected && !stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(1000, stoppingToken).ConfigureAwait(false);

                if (nrOfTimesCheckForConnectedState++ > 5)
                {
                    break;
                }
            }
        }
Example #9
0
        private async Task GenerateEntitiesAsyncInternal(NetDaemonHost daemonHost, string sourceFolder)
        {
            var services = await daemonHost.GetAllServices().ConfigureAwait(false);

            var entityIds = daemonHost.State.Distinct().ToList();

            var sourceRx = _codeGenerator.GenerateCodeRx(
                "NetDaemon.Generated.Reactive.Services",
                entityIds,
                services.ToList()
                );

            await File.WriteAllTextAsync(Path.Combine(sourceFolder, "_EntityExtensionsRx.cs.gen"), sourceRx).ConfigureAwait(false);
        }
Example #10
0
        /// <summary>
        ///     Default contructor
        /// </summary>
        public DaemonHostTestBase()
        {
            _loggerMock                = new LoggerMock();
            _defaultHassClientMock     = HassClientMock.DefaultMock;
            _defaultDataRepositoryMock = new Mock <IDataRepository>();

            _defaultHttpHandlerMock = new HttpHandlerMock();
            _defaultDaemonHost      = new NetDaemonHost(
                _defaultHassClientMock.Object,
                _defaultDataRepositoryMock.Object,
                _loggerMock.LoggerFactory,
                _defaultHttpHandlerMock.Object);

            _defaultDaemonHost.InternalDelayTimeForTts = 0; // Allow no extra waittime
        }
Example #11
0
        public ApiFakeStartup(IConfiguration configuration)
        {
            Configuration              = configuration;
            _loggerMock                = new LoggerMock();
            _defaultHassClientMock     = HassClientMock.DefaultMock;
            _defaultDataRepositoryMock = new Mock <IDataRepository>();
            _defaultHttpHandlerMock    = new HttpHandlerMock();
            var hassClientFactoryMock = new HassClientFactoryMock(_defaultHassClientMock);

            _defaultDaemonHost = new NetDaemonHost(
                hassClientFactoryMock.Object,
                _defaultDataRepositoryMock.Object,
                _loggerMock.LoggerFactory,
                _defaultHttpHandlerMock.Object);

            _defaultDaemonApp = new BaseTestApp
            {
                Id        = "app_id",
                IsEnabled = true
            };

            _defaultDaemonHost.AddRunningApp(_defaultDaemonApp);

            _defaultDaemonApp2 = new BaseTestApp
            {
                Id = "app_id2"
            };
            _defaultDaemonApp2.RuntimeInfo.NextScheduledEvent = DateTime.Now;
            _defaultDaemonApp2.IsEnabled = false;
            _defaultDaemonHost.AddRunningApp(_defaultDaemonApp2);

            _defaultDaemonRxApp = new BaseTestRxApp
            {
                Id        = "app_rx_id",
                IsEnabled = true
            };
            _defaultDaemonRxApp.RuntimeInfo.NextScheduledEvent = DateTime.Now;
            _defaultDaemonHost.AddRunningApp(_defaultDaemonRxApp);

            _defaultMockedRxApp = new Mock <NetDaemonRxApp>()
            {
                CallBase = true
            };
            _defaultMockedRxApp.Object.Id        = "app_rx_mock_id";
            _defaultMockedRxApp.Object.IsEnabled = true;
            _defaultMockedRxApp.Setup(n => n.CreateObservableIntervall(It.IsAny <TimeSpan>(), It.IsAny <Action>())).Returns(new Mock <IDisposable>().Object);
            _defaultDaemonHost.AddRunningApp(_defaultMockedRxApp.Object);
        }
Example #12
0
        public ApiFakeStartup(IConfiguration configuration)
        {
            Configuration              = configuration;
            _loggerMock                = new LoggerMock();
            _defaultHassClientMock     = HassClientMock.DefaultMock;
            _defaultDataRepositoryMock = new Mock <IDataRepository>();
            _defaultHttpHandlerMock    = new HttpHandlerMock();
            _defaultDaemonHost         = new NetDaemonHost(
                _defaultHassClientMock.Object,
                _defaultDataRepositoryMock.Object,
                _loggerMock.LoggerFactory,
                _defaultHttpHandlerMock.Object);

            _defaultDaemonApp           = new BaseTestApp();
            _defaultDaemonApp.Id        = "app_id";
            _defaultDaemonApp.IsEnabled = true;
            _defaultDaemonHost.InternalRunningAppInstances[_defaultDaemonApp.Id !] = _defaultDaemonApp;
Example #13
0
        public async Task ACustomEventShouldDoCorrectCall()
        {
            // ARRANGE
            var hcMock = HassClientMock.DefaultMock;

            await using var daemonHost = new NetDaemonHost(hcMock.Object, new Mock <IDataRepository>().Object);

            var app = new FluentTestApp();

            app.Id = "id";

            daemonHost.InternalRunningAppInstances[app.Id] = app;
            await app.StartUpAsync(daemonHost);

            dynamic dynObject = new ExpandoObject();

            dynObject.Test = "Hello World!";

            hcMock.AddCustomEvent("CUSTOM_EVENT", dynObject);

            var    cancelSource = hcMock.GetSourceWithTimeout();
            var    isCalled     = false;
            string?message      = "";

            app
            .Event("CUSTOM_EVENT")
            .Call((ev, data) =>
            {
                isCalled = true;
                message  = data?.Test;
                return(Task.CompletedTask);
            }).Execute();

            try
            {
                await daemonHost.Run("host", 8123, false, "token", cancelSource.Token).ConfigureAwait(false);
            }
            catch (TaskCanceledException)
            {
                // Expected behaviour
            }

            Assert.True(isCalled);
            Assert.Equal("Hello World!", message);
        }
Example #14
0
        public async Task GenerateEntitiesAsync(NetDaemonHost daemonHost, string sourceFolder)
        {
            if (!_netDaemonSettings.GenerateEntities.GetValueOrDefault())
            {
                return;
            }

            if (_entitiesGenerated)
            {
                return;
            }

            _logger.LogTrace("Generating entities from Home Assistant instance ..");

            _entitiesGenerated = true;

            await _codeGenerationHandler.GenerateEntitiesAsync(daemonHost, sourceFolder).ConfigureAwait(false);
        }
        public void FixStateTypesShouldReturnCorrectValues(
            bool result, object?newState, object?oldState, object?expectedNewState, object?expectedOldState)
        {
            var newEntityState = new EntityState
            {
                State = newState
            };
            var oldEntityState = new EntityState
            {
                State = oldState
            };

            bool res = NetDaemonHost.FixStateTypes(ref oldEntityState, ref newEntityState);

            Assert.Equal(result, res);
            Assert.Equal(expectedNewState, newEntityState.State);
            Assert.Equal(expectedOldState, oldEntityState.State);
        }
        /// <summary>
        ///     Default contructor
        /// </summary>
        public DaemonHostTestBase()
        {
            LoggerMock                = new LoggerMock();
            DefaultHassClientMock     = HassClientMock.DefaultMock;
            DefaultDataRepositoryMock = new Mock <IDataRepository>();
            DefaultHttpHandlerMock    = new HttpHandlerMock();
            var hassClientFactoryMock = new HassClientFactoryMock(DefaultHassClientMock);

            DefaultDaemonHost = new NetDaemonHost(
                hassClientFactoryMock.Object,
                DefaultDataRepositoryMock.Object,
                LoggerMock.LoggerFactory,
                DefaultHttpHandlerMock.Object,
                DefaultServiceProviderMock.Object
                )
            {
                InternalDelayTimeForTts = 0 // Allow no extra waittime
            };
        }
Example #17
0
        public async Task ACustomEventNullValueCallThrowsNullReferenceException()
        {
            // ARRANGE
            var hcMock = HassClientMock.DefaultMock;

            await using var daemonHost = new NetDaemonHost(hcMock.Object, new Mock <IDataRepository>().Object);

            var app = new FluentTestApp();

            app.Id = "id";

            daemonHost.InternalRunningAppInstances[app.Id] = app;
            await app.StartUpAsync(daemonHost);

            var cancelSource = hcMock.GetSourceWithTimeout();

            Assert.Throws <NullReferenceException>(() => app
                                                   .Event("CUSTOM_EVENT")
                                                   .Call(null).Execute());
        }
Example #18
0
 public TestCases(NetDaemonHost daemonHost, CancellationToken stoppingToken)
 {
     _daemonHost    = daemonHost;
     _stoppingToken = stoppingToken;
 }
Example #19
0
        private async Task Run(NetDaemonHost daemonHost, CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                try
                {
                    if (_hasConnectedBefore)
                    {
                        // This is due to re-connect, it must be a re-connect
                        // so delay before retry connect again
                        await Task.Delay(ReconnectInterval, stoppingToken).ConfigureAwait(false); // Wait x seconds

                        _logger.LogInformation($"Restarting NeDaemon service (version {Version})...");
                    }

                    var daemonHostTask = daemonHost.Run(
                        _homeAssistantSettings.Host,
                        _homeAssistantSettings.Port,
                        _homeAssistantSettings.Ssl,
                        _homeAssistantSettings.Token,
                        stoppingToken
                        );

                    if (!await WaitForDaemonToConnect(daemonHost, stoppingToken).ConfigureAwait(false))
                    {
                        continue;
                    }

                    if (!stoppingToken.IsCancellationRequested)
                    {
                        if (daemonHost.IsConnected)
                        {
                            try
                            {
                                // Generate code if requested
                                if (_sourcePath is string)
                                {
                                    await GenerateEntities(daemonHost, _sourcePath).ConfigureAwait(false);
                                }

                                if (_loadedDaemonApps is null)
                                {
                                    _loadedDaemonApps = _daemonAppCompiler.GetApps();
                                }

                                if (_loadedDaemonApps?.Any() != true)
                                {
                                    _logger.LogError("No NetDaemon apps could be found, exiting...");
                                    return;
                                }

                                IInstanceDaemonApp?codeManager = new CodeManager(_loadedDaemonApps, _logger, _yamlConfig);
                                await daemonHost.Initialize(codeManager).ConfigureAwait(false);

                                // Wait until daemon stops
                                await daemonHostTask.ConfigureAwait(false);
                            }
                            catch (TaskCanceledException)
                            {
                                _logger.LogTrace("Canceling NetDaemon service...");
                            }
                            catch (Exception e)
                            {
                                _logger.LogError(e, "Failed to load applications");
                            }
                        }
                        else
                        {
                            _logger.LogWarning($"Home Assistant Core still unavailable, retrying in {ReconnectInterval / 1000} seconds...");
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    if (!stoppingToken.IsCancellationRequested)
                    {
                        _logger.LogWarning($"Home assistant is disconnected, retrying in {ReconnectInterval / 1000} seconds...");
                    }
                }
                catch (Exception e)
                {
                    _logger.LogError("Error in NetDaemon service!, set trace log level to see details.");
                    _logger.LogTrace(e, "Error in NetDaemon service!");
                }
                finally
                {
                    try
                    {
                        await daemonHost.Stop().ConfigureAwait(false);
                    }
                    catch (Exception e)
                    {
                        _logger.LogError("Error stopping NetDaemonInstance, enable trace level logging for details");
                        _logger.LogTrace(e, "Error stopping NetDaemonInstance");
                    }
                }

                // If we reached here it could be a re-connect
                _hasConnectedBefore = true;
            }
        }
Example #20
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            try
            {
                _logger.LogInformation($"Starting NeDaemon (version {_version})...");

                var config = await ReadConfigAsync().ConfigureAwait(false);

                if (config == null)
                {
                    _logger.LogError("No config specified, file or environment variables! Exiting...");

                    return;
                }

                EnsureApplicationDirectoryExists(config);

                var sourceFolder  = config.SourceFolder;
                var storageFolder = Path.Combine(config.SourceFolder !, ".storage");

                sourceFolder = Path.Combine(config.SourceFolder !, "apps");

                // Automatically create source directories
                if (!System.IO.Directory.Exists(sourceFolder))
                {
                    System.IO.Directory.CreateDirectory(sourceFolder);
                }

                bool hasConnectedBefore = false;
                bool generatedEntities  = false;
                while (!stoppingToken.IsCancellationRequested)
                {
                    try
                    {
                        if (hasConnectedBefore)
                        {
                            // This is due to re-connect, it must be a re-connect
                            // so delay before retry connect again
                            await Task.Delay(_reconnectIntervall, stoppingToken).ConfigureAwait(false); // Wait x seconds
                        }

                        await using var _daemonHost = new NetDaemonHost(new HassClient(_loggerFactory), new DataRepository(storageFolder), _loggerFactory);

                        var daemonHostTask = _daemonHost.Run(config.Host, config.Port, config.Ssl, config.Token,
                                                             stoppingToken);

                        await WaitForDaemonToConnect(_daemonHost, stoppingToken).ConfigureAwait(false);

                        if (!stoppingToken.IsCancellationRequested)
                        {
                            if (_daemonHost.Connected)
                            {
                                try
                                {
                                    // Generate code if requested
                                    var envGenEntities = Environment.GetEnvironmentVariable("HASS_GEN_ENTITIES") ?? config.GenerateEntitiesOnStartup?.ToString();
                                    if (envGenEntities is object)
                                    {
                                        if (envGenEntities == "True" && !generatedEntities)
                                        {
                                            generatedEntities = true;
                                            var codeGen = new CodeGenerator();
                                            var source  = codeGen.GenerateCode("Netdaemon.Generated.Extensions",
                                                                               _daemonHost.State.Select(n => n.EntityId).Distinct());

                                            System.IO.File.WriteAllText(System.IO.Path.Combine(sourceFolder !, "_EntityExtensions.cs"), source);
                                        }
                                    }
                                    using (var codeManager = new CodeManager(sourceFolder !, _daemonHost.Logger))
                                    {
                                        await codeManager.EnableApplicationDiscoveryServiceAsync(_daemonHost, discoverServicesOnStartup : true).ConfigureAwait(false);

                                        // Wait until daemon stops
                                        await daemonHostTask.ConfigureAwait(false);

                                        if (!stoppingToken.IsCancellationRequested)
                                        {
                                            // It is disconnet, wait
                                            _logger.LogWarning($"Home assistant is unavailable, retrying in {_reconnectIntervall / 1000} seconds...");
                                        }
                                    }
                                }
                                catch (TaskCanceledException)
                                {
                                    _logger.LogInformation("Canceling NetDaemon service...");
                                }
                                catch (Exception e)
                                {
                                    _logger.LogError(e, "Failed to load applications");
                                }
                            }
                            else
                            {
                                _logger.LogWarning($"Home Assistant Core still unavailable, retrying in {_reconnectIntervall / 1000} seconds...");
                            }
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        if (!stoppingToken.IsCancellationRequested)
                        {
                            _logger.LogWarning($"Home assistant is disconnected, retrying in {_reconnectIntervall / 1000} seconds...");
                        }
                    }
                    // If we reached here it could be a re-connect
                    hasConnectedBefore = true;
                }
            }
            catch (OperationCanceledException)
            {
            } // Normal exit
            catch (Exception e)
            {
                _logger.LogError(e, "NetDaemon had unhandled exception, closing...");
            }

            _logger.LogInformation("Netdaemon exited!");
        }