自动充电策略实现

master
smartwyy 6 months ago
parent 5fc0ef3e16
commit 701daed9fe

@ -9,28 +9,8 @@ public class ExportDb
private static readonly string[] UsedTable =
{
"t_bs_charging_bin_info",
"t_bs_cloud_charge_model_recv_record",
"t_bs_cloud_elec_price_recv_record",
"t_bs_eqm_fault_base_info",
"t_bs_net_cloud_param_info",
"t_bs_net_eqm_param_info",
"t_bs_station_config_info",
"t_bs_station_elec_price_info",
"t_bs_station_info",
"t_cb_amt_order_info",
"t_cb_station_order_batt_log_info",
"t_cb_station_order_sended_log",
"t_cb_station_order_state_log",
"t_fl_repaired_info",
"t_fl_un_repair_info",
"t_rm_charger_record_report",
"t_ss_authority_to_role",
"t_ss_button_info",
"t_ss_menu_info",
"t_ss_role_info",
"t_ss_user_info",
"t_ss_user_to_role"
"elec_price_model_version",
"elec_price_model_version_detail"
};
private readonly SqlSugarClient Db = new(new ConnectionConfig
@ -56,7 +36,7 @@ public class ExportDb
}
Db.DbFirst
.Where(it => it.Contains("charge_order"))
.Where(it => UsedTable.Contains(it))
.IsCreateAttribute() //创建sqlsugar自带特性
.FormatFileName(ToPascalCase) //格式化文件名(文件名和表名不一样情况)
.FormatClassName(ToPascalCase) //格式化类名 (类名和表名不一样的情况)

@ -1,42 +1,14 @@
// See https://aka.ms/new-console-template for more information
using DotNetty.Codecs;
using DotNetty.Common.Internal.Logging;
using DotNetty.Handlers.Logging;
using DotNetty.Handlers.Timeout;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using ConsoleStarter;
using log4net.Config;
using Microsoft.Extensions.Logging;
using LogLevel = DotNetty.Handlers.Logging.LogLevel;
internal class Program
{
public static void Main(string[] args)
{
XmlConfigurator.ConfigureAndWatch(new FileInfo(AppDomain.CurrentDomain.BaseDirectory + @"\log4net.xml"));
InternalLoggerFactory.DefaultFactory.AddProvider(new Log4NetProvider());
Bootstrap bootstrap = new Bootstrap();
bootstrap
.Group(new MultithreadEventLoopGroup())
.Channel<TcpSocketChannel>()
.Option(ChannelOption.TcpNodelay, true)
.Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
{
var pipeline = channel.Pipeline;
pipeline.AddLast(new StringDecoder());
pipeline.AddLast(new StringEncoder());
// 监听器
pipeline.AddLast(new LoggingHandler(LogLevel.TRACE));
pipeline.AddLast("idleStateHandler", new IdleStateHandler(30, 0, 0)); // 触发读取超时
}));
Task<IChannel> task = bootstrap.ConnectAsync("127.0.0.1", 9998);
IChannel channel = task.Result;
channel.WriteAndFlushAsync("1111111111");
ExportDb exportDb = new ExportDb();
exportDb.Export();
}
}

@ -0,0 +1,83 @@
using System;
using System.Linq;
using System.Text;
using SqlSugar;
namespace Entity.DbModel.Station
{
///<summary>
///电价模型板板;电价模型版本表,生失效时间左开右闭且不能重叠
///</summary>
[SugarTable("elec_price_model_version")]
public partial class ElecPriceModelVersion
{
public ElecPriceModelVersion(){
}
/// <summary>
/// Desc:主键
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsPrimaryKey=true,IsIdentity=true,ColumnName="id")]
public int Id {get;set;}
/// <summary>
/// Desc:版本号;版本号,唯一
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName="version")]
public string Version {get;set;}
/// <summary>
/// Desc:生效时间;生效时间(左开右闭)
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName="start_time")]
public DateTime? StartTime {get;set;}
/// <summary>
/// Desc:失效时间;失效时间(左开右闭)
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName="end_time")]
public DateTime? EndTime {get;set;}
/// <summary>
/// Desc:创建人
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName="created_by")]
public string CreatedBy {get;set;}
/// <summary>
/// Desc:创建时间
/// Default:CURRENT_TIMESTAMP
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName="created_time")]
public DateTime? CreatedTime {get;set;}
/// <summary>
/// Desc:更新人
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName="updated_by")]
public string UpdatedBy {get;set;}
/// <summary>
/// Desc:更新时间
/// Default:CURRENT_TIMESTAMP
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName="updated_time")]
public DateTime? UpdatedTime {get;set;}
}
}

@ -0,0 +1,119 @@
using SqlSugar;
namespace Entity.DbModel.Station
{
///<summary>
///电价模型详情
///</summary>
[SugarTable("elec_price_model_version_detail")]
public partial class ElecPriceModelVersionDetail
{
public ElecPriceModelVersionDetail()
{
}
/// <summary>
/// Desc:id
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
public int Id { get; set; }
/// <summary>
/// Desc:版本号
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "version")]
public string Version { get; set; }
/// <summary>
/// Desc:开始时间
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "start_hour")]
public int StartHour { get; set; }
/// <summary>
/// Desc:开始时间
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "start_minute")]
public int StartMinute { get; set; }
/// <summary>
/// Desc:结束时间
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "end_hour")]
public int EndHour { get; set; }
/// <summary>
/// Desc:结束时间
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "end_minute")]
public int EndMinute { get; set; }
/// <summary>
/// Desc:价格;以分为单位存储
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "price")]
public int Price { get; set; }
/// <summary>
/// Desc:尖峰平谷类型;1-尖2-峰3-平4-谷
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "type")]
public int Type { get; set; }
/// <summary>
/// Desc:所需电池数量
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "battery_count")]
public int BatteryCount { get; set; }
/// <summary>
/// Desc:创建人
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "created_by")]
public string CreatedBy { get; set; }
/// <summary>
/// Desc:创建时间
/// Default:CURRENT_TIMESTAMP
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "created_time")]
public DateTime? CreatedTime { get; set; }
/// <summary>
/// Desc:更新人
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "updated_by")]
public string UpdatedBy { get; set; }
/// <summary>
/// Desc:更新时间
/// Default:CURRENT_TIMESTAMP
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "updated_time")]
public DateTime? UpdatedTime { get; set; }
}
}

@ -0,0 +1,20 @@
using Entity.DbModel.Station;
using HybirdFrameworkCore.Autofac.Attribute;
using SqlSugar;
namespace Repository.Station;
/// <summary>
///
/// </summary>
[Scope("SingleInstance")]
public class ElecPriceModelVersionDetailRepository : BaseRepository<ElecPriceModelVersionDetail>
{
/// <summary>
///
/// </summary>
/// <param name="sqlSugar"></param>
public ElecPriceModelVersionDetailRepository(ISqlSugarClient sqlSugar) : base(sqlSugar)
{
}
}

@ -0,0 +1,20 @@
using Entity.DbModel.Station;
using HybirdFrameworkCore.Autofac.Attribute;
using SqlSugar;
namespace Repository.Station;
/// <summary>
///
/// </summary>
[Scope("SingleInstance")]
public class ElecPriceModelVersionRepository : BaseRepository<ElecPriceModelVersion>
{
/// <summary>
///
/// </summary>
/// <param name="sqlSugar"></param>
public ElecPriceModelVersionRepository(ISqlSugarClient sqlSugar) : base(sqlSugar)
{
}
}

@ -34,7 +34,7 @@ public class ChargerClient : TcpClient<IBaseHandler, Decoder, Encoder>
public bool IsAuthed { get; set; } = false;
/// <summary>
/// 参考 ChargingStatus
/// 参考 Service.Charger.Common.ChargingStatus
/// </summary>
public UInt16 ChargingStatus { get; set; }
/// <summary>
@ -122,11 +122,11 @@ public class ChargerClient : TcpClient<IBaseHandler, Decoder, Encoder>
/// <summary>
/// 电池编码
/// </summary>
public string? BatterSn { get; set; }
public string? BatterNo { get; set; }
/// <summary>
/// 电池仓编号
/// </summary>
public int? BinNo { get; set; }
public string? BinNo { get; set; }
/// <summary>
/// 远程升级-监控网关上送升级完成确认帧
/// </summary>
@ -149,12 +149,14 @@ public class ChargerClient : TcpClient<IBaseHandler, Decoder, Encoder>
#region db
private ChargeOrderRepository _chargeOrderRepository;
private BinInfoRepository _binInfoRepository;
#endregion
public ChargerClient(ChargeOrderRepository chargeOrderRepository)
public ChargerClient(ChargeOrderRepository chargeOrderRepository, BinInfoRepository binInfoRepository)
{
_chargeOrderRepository = chargeOrderRepository;
_binInfoRepository = binInfoRepository;
}
/// <summary>
@ -350,14 +352,24 @@ public class ChargerClient : TcpClient<IBaseHandler, Decoder, Encoder>
/// </summary>
public Result<bool> StartCharge()
{
if (string.IsNullOrWhiteSpace(BinNo))
{
return Result<bool>.Fail("charger init error with no BinNo");
}
if (!Connected)
{
return Result<bool>.Fail($"充电机{BinNo}未连接");
return Result<bool>.Fail($"charger-{BinNo} disconnect");
}
if (string.IsNullOrWhiteSpace(BatterSn))
BinInfo binInfo = _binInfoRepository.QueryByClause(it => it.Code == BinNo);
if (binInfo == null)
{
return Result<bool>.Fail($"charger-{BinNo} not exist");
}
BatterNo = binInfo.BatteryNo;
if (string.IsNullOrWhiteSpace(BatterNo))
{
return Result<bool>.Fail($"充电仓{BinNo}电池不存在");
return Result<bool>.Fail($"charger-{BinNo} battery not exist");
}
RedisHelper redisHelper = AppInfo.Container.Resolve<RedisHelper>();
@ -365,7 +377,7 @@ public class ChargerClient : TcpClient<IBaseHandler, Decoder, Encoder>
string? lockKey = redisHelper.GetStrValue($"chargeNo{BinNo}Start");
if (!string.IsNullOrWhiteSpace(lockKey))
{
return Result<bool>.Fail($"充电仓{BinNo}正在启动中");
return Result<bool>.Success($"charger-{BinNo} is starting");
}
redisHelper.SetKeyValueStr($"chargeNo{BinNo}Start", DateTime.Now.ToString("f"), TimeSpan.FromMinutes(1));
@ -376,9 +388,9 @@ public class ChargerClient : TcpClient<IBaseHandler, Decoder, Encoder>
_chargeOrderRepository.Insert(new ChargeOrder()
{
Sn = chargeOrderNo,
BatteryNo = BatterSn,
BatteryNo = BatterNo,
CmdStatus = 0,
ChargerNo = (BinNo??-1).ToString(),
ChargerNo = BinNo,
ChargeMode = 1,
StartMode = 1
});

@ -3,6 +3,7 @@ using DotNetty.Transport.Channels;
using Entity.DbModel.Station;
using HybirdFrameworkCore.Autofac;
using HybirdFrameworkCore.Autofac.Attribute;
using HybirdFrameworkCore.Entity;
using HybirdFrameworkDriver.Session;
using log4net;
using Repository.Station;
@ -73,6 +74,60 @@ public static class ClientMgr
}
}
/// <summary>
///
/// </summary>
public static void StartAutoChargeThread()
{
Thread thread = new Thread(AutoChargeThread)
{
Name = @"auto-charge"
};
thread.Start();
}
/// <summary>
///
/// </summary>
private static void AutoChargeThread()
{
ElecPriceModelVersionRepository elecPriceModelVersionRepository =
AppInfo.Container.Resolve<ElecPriceModelVersionRepository>();
ElecPriceModelVersionDetailRepository elecPriceModelVersionDetailRepository =
AppInfo.Container.Resolve<ElecPriceModelVersionDetailRepository>();
while (true)
{
Thread.Sleep(1000 * 30);
DateTime now = DateTime.Now;
ElecPriceModelVersion elecPriceModelVersion = elecPriceModelVersionRepository.QueryByClause(i => i.StartTime >= now && i.EndTime < now);
if (elecPriceModelVersion == null)
{
Log.Info("lack of effective elec price model");
continue;
}
List<ElecPriceModelVersionDetail> elecPriceModelVersionDetails = elecPriceModelVersionDetailRepository.QueryListByClause(it => it.Version == elecPriceModelVersion.Version);
ElecPriceModelVersionDetail? elecPriceModelVersionDetail = elecPriceModelVersionDetails.Where(i => i.StartHour <= now.Hour && i.StartMinute <= now.Minute
&& i.EndHour > now.Hour &&
i.EndMinute > now.Minute).FirstOrDefault();
if (elecPriceModelVersionDetail == null)
{
Log.Info("lack of effective elec price model detail");
continue;
}
//int batteryCount = elecPriceModelVersionDetail.BatteryCount;
foreach (KeyValuePair<string,ChargerClient> pair in Dictionary)
{
Result<bool> result = pair.Value.StartCharge();
Log.Info($"start {pair.Key} charge {result.IsSuccess}:{result.Msg}");
}
}
}
private static void ConnClient(EquipNetInfo netInfo)
{
Log.Info($"begin to connect {netInfo.Code} {netInfo.NetAddr}:{netInfo.NetPort}");

@ -29,7 +29,7 @@ namespace Service.Charger.Handler
sb.Append(Convert.ToChar(b));
}
client.BatterSn = sb.ToString();
client.BatterNo = sb.ToString();
Log.Info($"receive {msg} from {sn}");
}

@ -73,7 +73,7 @@ namespace Service.Charger.Handler
ChargeOrder chargeOrder = new ChargeOrder()
{
Sn = client.ChargeOrderNo,
BatteryNo = client.BatterSn,
BatteryNo = client.BatterNo,
StartTime = new DateTime((msg.StartYear+1900) , msg.StartMonth ,msg.StartDay ,msg.StartHour, msg.StartMinute, msg.StartSecond),
EndTime = new DateTime(msg.EndYear + 1900, msg.EndMonth, msg.EndDay, msg.EndHour, msg.EndMinute, msg.EndSecond),
StartSoc = msg.SocBefore,

@ -53,12 +53,35 @@ public class StaticStationInfo
set => Set(StationParamConst.SwapSoc, value);
}
#region 充电相关
public static byte ChargeSoc
{
get => byte.Parse(Resolve(StationParamConst.ChargeSoc));
set => Set(StationParamConst.ChargeSoc, value);
}
/// <summary>
/// 0-关闭 1-开启
/// </summary>
public static byte AutoChargeEnabled
{
get => byte.Parse(Resolve(StationParamConst.AutoChargeEnabled));
set => Set(StationParamConst.AutoChargeEnabled, value);
}
/// <summary>
/// 最低满电电池数量
/// </summary>
public static int BatteryNeedCount
{
get => int.Parse(Resolve(StationParamConst.BatteryNeedCount));
set => Set(StationParamConst.BatteryNeedCount, value);
}
#endregion
#region cloud

@ -13,6 +13,8 @@ public class StationParamConst
//充电soc
public static readonly string ChargeSoc = "Station.ChargeSoc";
public static readonly string AutoChargeEnabled = "Station.AutoChargeEnabled";
public static readonly string BatteryNeedCount = "Station.BatteryNeedCount";
public static readonly string StationStatus = "Station.StationStatus";

@ -105,7 +105,7 @@ public partial class Form2 : Form
private void DisplayData()
{
this.SetText(this.rTxtData, JsonConvert.SerializeObject(_chargerClient, Formatting.Indented));
this.lblBatterNo.Text = _chargerClient?.BatterSn;
this.lblBatterNo.Text = _chargerClient?.BatterNo;
}
private void btnConn_Click(object sender, EventArgs e)

Loading…
Cancel
Save