Files

317 lines
12 KiB
C#

///
/// Copyright (c) 2017-2022 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using Common;
using Config.Entities;
using SchematicDrawing;
using TBF.Rig.GenericDevices;
using TBF.Boxes;
namespace TBF.Rig.Modbus.TempControl.Easytherm
{
public class TControl : ComponentBase, Generic.IDevice, ITempControl, ISequenceCondition,
IDrawingItCmpntWithSetpoint, IDrawingItCmpntWithMeasuredVal, IDrawingItCmpntWithCustomBmp
{
private static readonly ILog log = LogManager.GetLogger(typeof(TControl));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
readonly TControlCfg easythermCfg;
public IDrawingItem DrawingItem { get { return easythermCfg as IDrawingItem; } }
Common.Modbus modbus;
int ticketNumber; /// 0 .. number of devices registered for regular polling - 1
public bool MsrmntAvailable { get { return true; } }
public double MeasuredVal { get { return ReadTemperature(); } }
public double MsrdValLimLo { get { return Units.ConvertFrom(MsrdUnit, easythermCfg.MsrdValLimLo); } }
public double MsrdValLimHi { get { return Units.ConvertFrom(MsrdUnit, easythermCfg.MsrdValLimHi); } }
public Unit MsrdUnit { get { return easythermCfg.MsrdUnit; } }
public string MsrdFormat { get { return easythermCfg.MsrdFormat; } }
public string AltString { get { return string.Empty; } }
public double SetpointVal
{
get { return temperatureSetPoint; }
set { SetTemperatureSetpoint(value); }
}
///
public void IncreaseSetpoint()
{
double tempStepC = isFahrenheit ? Units.ConvertFrom(Unit.F, easythermCfg.SetpStep) : easythermCfg.SetpStep;
double newSetpoint;
if (easythermCfg.RoundToSetpStep)
{
double roundedSetpoint = tempStepC * Math.Round(temperatureSetPoint / tempStepC);
newSetpoint = (roundedSetpoint <= temperatureSetPoint) ? (roundedSetpoint + tempStepC) : roundedSetpoint;
}
else
{
newSetpoint = temperatureSetPoint + tempStepC;
}
SetTemperatureSetpoint(Math.Min(newSetpoint, 95.0));
}
///
public void DecreaseSetpoint()
{
double tempStepC = isFahrenheit ? Units.ConvertFrom(Unit.F, easythermCfg.SetpStep) : easythermCfg.SetpStep;
double newSetpoint;
if (easythermCfg.RoundToSetpStep)
{
double roundedSetpoint = tempStepC * Math.Round(temperatureSetPoint / tempStepC);
newSetpoint = (roundedSetpoint >= temperatureSetPoint) ? (roundedSetpoint - tempStepC) : roundedSetpoint;
}
else
{
newSetpoint = temperatureSetPoint - tempStepC;
}
SetTemperatureSetpoint(Math.Max(newSetpoint, 5.0));
}
public DrawingShape GetCustomBitmap()
{
switch (easythermCfg.Sz)
{
case Sz.S:
return isHeating ? (isCooling ? TControlCfg.DSBothS : TControlCfg.DSHeatingS)
: (isCooling ? TControlCfg.DSCoolingS : TControlCfg.DSIdleS);
case Sz.M:
return isHeating ? (isCooling ? TControlCfg.DSBothM : TControlCfg.DSHeatingM)
: (isCooling ? TControlCfg.DSCoolingM : TControlCfg.DSIdleM);
default:
case Sz.L:
return isHeating ? (isCooling ? TControlCfg.DSBothL : TControlCfg.DSHeatingL)
: (isCooling ? TControlCfg.DSCoolingL : TControlCfg.DSIdleL);
case Sz.XL:
return isHeating ? (isCooling ? TControlCfg.DSBothXL : TControlCfg.DSHeatingXL)
: (isCooling ? TControlCfg.DSCoolingXL : TControlCfg.DSIdleXL);
}
}
private double temperatureSetPoint;
private bool temperatureSetPointValid;
private bool temperatureSetPointRequested;
double actualTemperature;
bool isHeating { get { return false; } } /// TODO: ??? Output x: Heating
bool isCooling { get { return false; } } /// TODO: ??? Output y: Cooling
bool isFahrenheit { get { return false; } }
public TControl() { }
public TControl(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
easythermCfg = cfg as TControlCfg;
CreateConditions(true);
}
/// <summary>Initialize this device</summary>
public override void Initialize()
{
modbus = TbfComponents.FindComponent(easythermCfg.ParentName) as Common.Modbus;
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
temperatureSetPointValid = false;
temperatureSetPointRequested = false;
modbus.ComponentNames[easythermCfg.ModbusAddress] = Name;
ticketNumber = modbus.RegisterForPolling();
log.FatalFormat("{0} initialized: {1}", Name, this);
}
/// <summary>Run this device</summary>
public void RunDeviceBefore()
{
if (modbus.ReceivedTelegrams[easythermCfg.ModbusAddress].Count > 0)
{
byte[] telegram = modbus.ReceivedTelegrams[easythermCfg.ModbusAddress].Dequeue();
if (telegram.Length == 7 && telegram[1] == (byte)Function.ReadHoldingRegisters && telegram[2] == 2)
{
ushort value = (ushort)(256 * telegram[3] + telegram[4]);
temperatureSetPoint = Convert.ToDouble(value) * 0.04;
temperatureSetPointValid = true;
log.InfoFormat("{0} - Received current temperature setpoint = {1}", Name, temperatureSetPoint);
}
else if (telegram.Length == 7 && telegram[1] == (byte)Function.ReadInputRegister && telegram[2] == 2)
{
ushort value = (ushort)(256 * telegram[3] + telegram[4]);
actualTemperature = Convert.ToDouble(value) * 0.04;
log.InfoFormat("{0} - Received actual temperature = {1}", Name, actualTemperature);
}
}
}
public void RunDeviceAfter()
{
if (DebugLevel != DebugMode.Simulate && DebugLevel != DebugMode.FailureDuringOperation &&
modbus.IsMyTurn(ticketNumber))
{
if (!temperatureSetPointValid && !temperatureSetPointRequested)
{
//RequestTemperatureSetpoint();
temperatureSetPointRequested = true;
}
/// TODO: ???
//else if (temperatureSetPointValid && requiredTemp != temperatureSetPoint)
//{
// SetTemperatureSetpoint(requiredTemp);
// log.InfoFormat("{0} - Set new temperature setpoint = {1}", Name, requiredTemp);
//}
//else if (modbus.IsMyTurn(ticketNumber))
//{
// RequestActualTemperature();
//}
}
}
public void StopDevice() { }
public void StopDevice2() { }
/// <summary>
/// Set Easytherm controller to specified temperature
/// </summary>
/// <param name="temperatureC">Temperature in °C</param>
/// <returns>true = OK, false = any error</returns>
public bool SetTemperatureSetpoint(double temperatureC)
{
if (temperatureC != 0 && (temperatureC < 5.0 || temperatureC > 95.0))
{
return false; /// required temperature out of range
}
if (temperatureSetPointValid && (temperatureC == temperatureSetPoint))
{
return true; /// already set to the required temperature
}
if (temperatureC != 0) /// temperature==0 disables sending the setpoint
{
//ushort temperatureSetpoint = (ushort)temperature; // in °C
//ushort destAddress = (ushort)1002;
ushort usTempSetpoint = (ushort)((10000.0f / 400.0f) * temperatureC); // in 0.01% of range (400 °C)
ushort destAddress = (ushort)2;
///
SendValueToEasytherm(Function.PresetSingleRegister, destAddress, usTempSetpoint);
}
temperatureSetPoint = temperatureC;
temperatureSetPointValid = true;
return true;
}
public void RequestActualTemperature()
{
SendValueToEasytherm(Function.ReadInputRegister, (ushort)0, (ushort)1); // rel.address=x, 1 word
}
void SendValueToEasytherm(Function function, ushort address, ushort value)
{
byte[] msg = new byte[8];
msg[0] = (byte)easythermCfg.ModbusAddress;
msg[1] = (byte)function;
msg[2] = (byte)(address >> 8); /// Relative address Hi
msg[3] = (byte)(address & 0xFF); /// Relative address Lo
msg[4] = (byte)(value >> 8); /// Data Hi
msg[5] = (byte)(value & 0xFF); /// Data Lo
modbus.SendMessage(msg, Name);
}
///
/// Operations, etc.
///
public double ReadTemperature()
{
return actualTemperature;
}
/// <summary>
/// Events: SetOpututsDone, Error
/// </summary>
/// <returns>SetOutputsOp instance reference casted to IOperaton</returns>
public IOperation SetTemperatureSetpointOp(double temperature)
{
return new SetTemperatureSetpointOp(this, temperature);
}
public IOperation ReadTempOp(ref DoubleBox temp)
{
return new ReadTempOp(this, ref temp);
}
public IOperation ReadTempOp(ref DoubleBox temp, Event eventDone)
{
return new ReadTempOp(this, ref temp, eventDone);
}
///
/// ISequenceCondition interface implementation (conditions in transition sequences)
///
IList<string> sequenceConditionNames;
IList<IOperation> sequenceConditions;
public int ConditionsCount { get { return sequenceConditions != null ? sequenceConditions.Count : 0; } }
/// Strings are added to the combo-box for transition sequence condition selection
public string ConditionName(int i)
{
if (sequenceConditionNames != null && i < sequenceConditionNames.Count && i >= 0)
return sequenceConditionNames[i];
else
return string.Empty;
}
/// Operations are executed as a part of a transition sequence
public IOperation ConditionOp(int i)
{
if (sequenceConditions != null && i < sequenceConditions.Count && i >= 0)
return sequenceConditions[i];
else
return null;
}
void ClearConditions()
{
sequenceConditionNames = new List<string>();
sequenceConditions = new List<IOperation>();
}
void AddCondition(string conditionName, bool createOperation, IOperation conditionOperation)
{
sequenceConditionNames.Add(conditionName);
if (createOperation) sequenceConditions.Add(conditionOperation);
}
/// <summary>
/// Create a list of conditions
/// </summary>
/// <param name="createOps">true = create names and condition operations, false = create names only</param>
void CreateConditions(bool createOps)
{
ClearConditions();
AddCondition("Set temperature setpoint A", createOps, SetTemperatureSetpointOp(easythermCfg.ProcParams.Temp_A));
AddCondition("Set temperature setpoint B", createOps, SetTemperatureSetpointOp(easythermCfg.ProcParams.Temp_B));
AddCondition("Set temperature setpoint C", createOps, SetTemperatureSetpointOp(easythermCfg.ProcParams.Temp_C));
AddCondition("Set temperature setpoint D", createOps, SetTemperatureSetpointOp(easythermCfg.ProcParams.Temp_D));
AddCondition("Set temperature setpoint E", createOps, SetTemperatureSetpointOp(easythermCfg.ProcParams.Temp_E));
}
}
}