Esempio n. 1
0
        private async Task PostAdjustedCurrent(float fNewChargeCurrent, ChargerCache cCache)
        {
            string sNewChargeCurrent = fNewChargeCurrent.ToString();

            if (cCache.fCurrentSet != fNewChargeCurrent)
            {
                LogInformation($"Adjusting {sTestPrefix}{cCache.sName} to {sNewChargeCurrent}A");
                await MqttClnt.PublishAsync($"{sTestPrefix}{cCache.sName}/set/current",
                                            sNewChargeCurrent,
                                            MqttQualityOfServiceLevel.AtLeastOnce,
                                            false);

                LogInformation($"Adjusted {sTestPrefix}{cCache.sName} to {sNewChargeCurrent}A");
            }
            else
            {
                LogInformation($"{sTestPrefix}{cCache.sName} already at {sNewChargeCurrent}A");
            }

            //TODO Store in database
        }
Esempio n. 2
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");
        }