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 }
//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"); }