Beispiel #1
0
        //Automatically passes the logger factory in to the constructor via dependency injection
        public MQTTService(ILogger <MQTTService> log, IServiceProvider serviceProvider)
        {
            //Get serviceprovider so we later can connect to databasemodel from it.
            _serviceProvider = serviceProvider;
            _log             = log;

            //log=_serviceProvider.GetRequiredService()

            culture = CultureInfo.CreateSpecificCulture("sv-SE");

            //fMeanCurrent=new float[4];
            bcLookup = new Dictionary <string, BaseCache>();
            string sBrokerURL, sBrokerUser, sBrokerPasswd = "";

            Factory = new MqttFactory();

            MqttClnt = Factory.CreateMqttClient();

/*
 *          log = loggerFactory?.CreateLogger("MQTTSvc");
 *          if(log == null)
 *          {
 *              throw new ArgumentNullException(nameof(loggerFactory));
 *          }
 */
            using (var scope = _serviceProvider.CreateScope())
            {
                dbContext = scope.ServiceProvider.GetService <ApplicationDbContext>();

                //Read all of the config
                appConfig = dbContext.Configuration.ToList();

                sBrokerURL    = GetConfigString("BrokerURL");
                sBrokerUser   = GetConfigString("BrokerUser");
                sBrokerPasswd = GetConfigString("BrokerPasswd");
                sTestPrefix   = GetConfigString("TestPrefix");

                try {
                    var assignments = dbContext.CMPAssignments
                                      .Include(m => m.Meter)
                                      .Include(p => p.Partner)
                                      .Include(c => c.Charger)
                                      .AsNoTracking();

                    foreach (var assignItem in assignments)
                    {
                        var meitem = assignItem.Meter;
                        var paitem = assignItem.Partner;
                        var chitem = assignItem.Charger;

                        try
                        {
                            MeterCache meterCache = new MeterCache();
                            meterCache.sName       = meitem.Name;
                            meterCache.sCustomerID = paitem.UserReference;
                            meterCache.fMaxCurrent = meitem.MaxCurrent;
                            bcLookup.Add(meitem.Name, meterCache);

                            ChargerCache chargerCache = new ChargerCache();
                            chargerCache.sCustomerID = paitem.UserReference;
                            chargerCache.fMaxCurrent = chitem.MaxCurrent;
                            chargerCache.bcParent    = meterCache;
                            chargerCache.sName       = chitem.Name;
                            chargerCache.iPhases     = 7;
                            meterCache.cChildren.Add(chargerCache);
                            bcLookup.Add(chitem.Name, chargerCache);
                        }
                        catch (System.Exception e)
                        {
                            _log.LogError(e.Message);
                        }
                    }
                } catch (Exception e) {
                    _log.LogWarning(e.Message);
                    //fMaxCurrent=-1;
                    LogInformation($"MaxCurrent error: {e.Message}");
                }
                LogInformation($"BrokerURL:{sBrokerURL}");
            }

            //MqttNetGlobalLogger.LogMessagePublished += OnTraceMessagePublished;
            options = new MqttClientOptionsBuilder()
                      .WithClientId("EnergyApp")
                      .WithTcpServer(sBrokerURL)
                      .WithCredentials(sBrokerUser, sBrokerPasswd)
                      .Build();

            //var result = MqttClnt.ConnectAsync(options);
            #region UseConnectedHandler
            MqttClnt.UseConnectedHandler(async e =>
            {
                Console.WriteLine("### CONNECTED TO SERVER ###");
                // Subscribe to topics
                foreach (string Name in bcLookup.Keys)
                {
                    if (Name.Contains("EVC"))
                    {
                        await MqttClnt.SubscribeAsync(new TopicFilterBuilder().WithTopic($"{Name}/#").Build());
                    }
                }
                for (int i = 1; i < 4; i++)
                {
                    await MqttClnt.SubscribeAsync(new TopicFilterBuilder().WithTopic($"+/status/current_l{i}/#").Build());
                }

                Console.WriteLine("### SUBSCRIBED ###");
            });
            #endregion

            MqttClnt.UseDisconnectedHandler(async e =>
            {
                Console.WriteLine("### DISCONNECTED FROM SERVER ###");
                await Task.Delay(TimeSpan.FromSeconds(5));
                try
                {
                    await MqttClnt.ConnectAsync(options);
                }
                catch
                {
                    Console.WriteLine("### RECONNECTING FAILED ###");
                }
            });

            MqttClnt.UseApplicationMessageReceivedHandler(e =>
            {
                LogInformation($"IncomingMsg;{e.ApplicationMessage.Topic};{Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");

                //Find charger from chargername or meter from metername
                string[] topic = e.ApplicationMessage.Topic.Split('/');

                BaseCache mc;
                try
                {
                    mc = bcLookup[topic[0]];
                }
                catch (System.Exception)
                {
                    LogInformation($"Cannot find {topic[0]}");
                    mc = null;
                }
                //TODO What happens if not found

                //Check current from the highest meter to the charger
                if (mc is MeterCache)
                {
                    MeterCache mCache = (MeterCache)mc;
                    if (e.ApplicationMessage.Topic.Contains("current_l"))
                    {
                        //Get info in temp vars
                        var fCurrent = ToFloat(e.ApplicationMessage.Payload);
                        int iPhase   = Int16.Parse(e.ApplicationMessage.Topic.Substring(e.ApplicationMessage.Topic.Length - 1));

                        //Store in cache
                        mCache.fMeterCurrent[iPhase] = fCurrent;
                        mCache.fMeanCurrent[iPhase]  = (2 * mCache.fMeanCurrent[iPhase] + fCurrent) / 3;
                        LogInformation($"Phase: {iPhase}; Current: {fCurrent}; Mean Current: {mCache.fMeanCurrent[iPhase]}");
                        float fSuggestedCurrentChange;
                        //Calculate new value
                        if (fCurrent > mCache.fMaxCurrent)
                        {
                            //What's the overcurrent?
                            float fOverCurrent = fCurrent - mCache.fMaxCurrent;
                            LogInformation($"Holy Moses, {fCurrent} is {fOverCurrent}A too much!");

                            //Check all chargers that is connected
                            var connChargers = mCache.cChildren.Where(m => m.bConnected);

                            //Set new current
                            //Number of chargers to even out on
                            int iChargers = connChargers.Count();

                            fSuggestedCurrentChange = (-fOverCurrent) / iChargers;

                            foreach (ChargerCache cc in connChargers)
                            {
                                //TODO Handle the case where one charger uses less current than given.
                                //TODO Distribute to the others.

                                float fNewCurrent = cc.AdjustNewChargeCurrent(fSuggestedCurrentChange);

                                //TODO Might hang with await
                                PostAdjustedCurrent(fNewCurrent, cc);
                            }
                            LogInformation($"New charging current for {mCache.sName}");
                        }
                        else
                        {
                            //Loop through chargers and outlets

                            /*
                             * foreach (var charger in mCache.cChildren)
                             * {
                             *  if(fCurrent>charger.fMaxCurrent) {
                             *      float fOverCurrent=fCurrent-mCache.fMaxCurrent;
                             *      _logger.LogInformation($"Holy Charger, {fCurrent} is {fOverCurrent}A too much!");
                             *      fNewChargeCurrent=(charger.fMaxCurrent-fOverCurrent);
                             *      await AdjustCurrent(fNewChargeCurrent, charger);
                             *  }
                             * }
                             */
                        }
                    }
                }
                else if (mc is ChargerCache)
                {
                    var cCache = (ChargerCache)mc;
                    if (e.ApplicationMessage.Topic.Contains("/status/current"))
                    {
                        cCache.fCurrentSet = ToFloat(e.ApplicationMessage.Payload);
                        LogInformation($"Got charger current:{cCache.fCurrentSet}");
                    }
                    else if (e.ApplicationMessage.Topic.Contains("/status/max_current"))
                    {
                        cCache.fMaxCurrent = ToFloat(e.ApplicationMessage.Payload);
                        LogInformation($"Got charger maxcurrent:{cCache.fMaxCurrent}");
                    }
                    else if (e.ApplicationMessage.Topic.Contains("/status/charging"))
                    {
                        cCache.bConnected = ToBool(e.ApplicationMessage.Payload);
                        LogInformation($"Got charger charging:{cCache.bConnected}");

                        using (var scope = _serviceProvider.CreateScope())
                        {
                            dbContext = scope.ServiceProvider.GetService <ApplicationDbContext>();

                            var chSession = new ChargeSession();

                            chSession.ChargerID = 1;
                            chSession.ID        = 1;
                            chSession.OutletID  = 1;
                            chSession.Kwh       = 10;

                            dbContext.ChargeSession.Add(chSession);
                            dbContext.SaveChanges();
                        }
                    }
                }

                if (e.ApplicationMessage.Topic.Contains("current1d"))
                {
                    //Save PNG to file

                    Stream s = new FileStream("1d.png", FileMode.Create);
                    var bw   = new BinaryWriter(s);
                    bw.Write(e.ApplicationMessage.Payload);
                    //bw.Flush();
                    bw.Close();
                }
                LogInformation($"Receive end");
            });

            LogInformation("MQTTService created");
        }
Beispiel #2
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                dbContext = scope.ServiceProvider.GetService <ApplicationDbContext>();

                var test = dbContext.Meters.AsQueryable();
            }

            LogInformation("Background thread started");

            var result = await MqttClnt.ConnectAsync(options);

            LogInformation($"Connection result: {result.ResultCode}");

            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(30000, stoppingToken);

                //Check if we can increase the charge current
                //Loop through meters
                foreach (BaseCache cCache in bcLookup.Values)
                {
                    if (cCache is MeterCache)
                    {
                        MeterCache mc = (MeterCache)cCache;

                        //Get max current we can increase with
                        //Checks all phases
                        LogInformation($"{mc.sName}, checking possible currentChange");
                        //TODO Check one phase at a time
                        float fSuggestedCurrentChange = mc.GetMaxPhaseAddCurrent(7);

                        //Check all chargers that is connected
                        var connChargers = mc.cChildren.Where(m => m.bConnected);

                        //Set new current
                        //Number of chargers to even out on
                        int iChargers = connChargers.Count();

                        LogInformation($"{mc.sName}, possible currentChange for {iChargers} chargers: {fSuggestedCurrentChange}A");

                        fSuggestedCurrentChange = fSuggestedCurrentChange / iChargers;

                        foreach (ChargerCache cc in connChargers)
                        {
                            //TODO Handle the case where one charger uses less current than given.
                            //TODO Distribute to the others.

                            float fNewCurrent = cc.AdjustNewChargeCurrent(fSuggestedCurrentChange);
                            await PostAdjustedCurrent(fNewCurrent, cc);
                        }
                    }
                }
                LogInformation($"Background svc loop end");
            }

            stoppingToken.Register(() => LogInformation($" MQTTSvc background task is stopping."));


/* Python rules
 *  client.subscribe("EVCharger/#")
 *  client.subscribe("CurrentMeter/#")
 *
 *
 *  if msg.topic == "EVCharger/status/current":
 *      charge_current = float(msg.payload)
 *      print("Charge current %.1f A" % charge_current)
 *  if msg.topic == "CurrentMeter/status/current":
 *      current = float(msg.payload)
 *      mean_current = (9*mean_current + current) / 10
 *      print("Current %.1f (mean %.1f)" % (current, mean_current))
 *      if mean_current > max_current:
 *          new_charge_current = charge_current - (mean_current-max_current)
 *          client.publish("EVCharger/set/current", payload=str(int(new_charge_current)), qos=0, retain=False)
 *          if new_charge_current < 2:
 *              client.publish("EVCharger/set/enable", payload=str(0), qos=0, retain=False)
 *      else:
 *          client.publish("EVCharger/set/current", payload=str(int(max_current)), qos=0, retain=False)
 *          client.publish("EVCharger/set/enable", payload=str(1), qos=0, retain=False)
 */
            //MqttClient client=(MqttClient)MqttClnt;

            //result = await MqttClnt.ConnectAsync(options);

/*            async Task Handler1(MqttApplicationMessageReceivedEventArgs e)
 *          {
 * //                await client1.PublishAsync($"reply/{eventArgs.ApplicationMessage.Topic}");
 *              string _logstr=$"{DateTime.Now} {e.ApplicationMessage.Topic} \t {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}";
 *              //Logger.LogInformation(logstr);
 *              Console.WriteLine(logstr);
 *          }
 *
 *          client.UseApplicationMessageReceivedHandler(Handler1);
 *          while (!stoppingToken.IsCancellationRequested)
 *          {
 *              await Task.Delay(1000, stoppingToken);
 *
 *              Console.WriteLine("Background svc looping");
 *
 *          }
 */

            Console.WriteLine("Background svc is stopping.");

            //return Task.CompletedTask;
        }