TOU
This commit is contained in:
parent
e0d6d04409
commit
372ab2203d
|
|
@ -1894,7 +1894,15 @@ public class Controller : ControllerBase
|
|||
public async Task<ActionResult<IEnumerable<Object>>> EditInstallationConfig([FromBody] Configuration config, Int64 installationId,int product,Token authToken)
|
||||
{
|
||||
var session = Db.GetSession(authToken);
|
||||
|
||||
|
||||
// Dynamic Pricing in Spot Price mode: forward the provider chosen on the Information tab
|
||||
// so the device knows which operator's API to query for spot prices.
|
||||
if (config.DynamicPricingMode == "SpotPrice")
|
||||
{
|
||||
var installation = Db.GetInstallationById(installationId);
|
||||
config.NetworkProvider = installation?.NetworkProvider;
|
||||
}
|
||||
|
||||
string configString = product switch
|
||||
{
|
||||
0 => config.GetConfigurationSalimax(), // Salimax
|
||||
|
|
|
|||
|
|
@ -24,9 +24,15 @@ public class Configuration
|
|||
|
||||
// Sinexcel Dynamic Pricing (under GridPriority) — strings for demo; engine will parse later.
|
||||
public string? DynamicPricingMode { get; set; }
|
||||
public string? NetworkProvider { get; set; }
|
||||
public string? CurrentPrice { get; set; }
|
||||
public string? PriceToSell { get; set; }
|
||||
public string? PriceToBuy { get; set; }
|
||||
// TOU windows stored as "HH:mm" strings
|
||||
public string? TimeToSellFrom { get; set; }
|
||||
public string? TimeToSellTo { get; set; }
|
||||
public string? TimeToBuyFrom { get; set; }
|
||||
public string? TimeToBuyTo { get; set; }
|
||||
|
||||
public String GetConfigurationString()
|
||||
{
|
||||
|
|
@ -55,7 +61,8 @@ public class Configuration
|
|||
return $"MinimumSoC: {MinimumSoC}, MaximumDischargingCurrent: {MaximumDischargingCurrent}, MaximumChargingCurrent: {MaximumChargingCurrent}, OperatingPriority: {OperatingPriority}, " +
|
||||
$"InverterNumber: {InverterNumber}, BatteriesCount: {BatteriesCount}, BatteriesCountPerInverter: [{(BatteriesCountPerInverter != null ? string.Join(", ", BatteriesCountPerInverter) : "")}], ClusterNumber: {ClusterNumber}, PvNumber: {PvNumber}, ControlPermission:{ControlPermission}, "+
|
||||
$"SinexcelTimeChargeandDischargePower: {TimeChargeandDischargePower}, SinexcelStartTimeChargeandDischargeDayandTime: {StartTimeChargeandDischargeDayandTime}, SinexcelStopTimeChargeandDischargeDayandTime: {StopTimeChargeandDischargeDayandTime}, " +
|
||||
$"DynamicPricingMode: {DynamicPricingMode}, CurrentPrice: {CurrentPrice}, PriceToSell: {PriceToSell}, PriceToBuy: {PriceToBuy}";
|
||||
$"DynamicPricingMode: {DynamicPricingMode}, NetworkProvider: {NetworkProvider}, CurrentPrice: {CurrentPrice}, PriceToSell: {PriceToSell}, PriceToBuy: {PriceToBuy}, " +
|
||||
$"TimeToSell: {TimeToSellFrom}-{TimeToSellTo}, TimeToBuy: {TimeToBuyFrom}-{TimeToBuyTo}";
|
||||
}
|
||||
|
||||
// TODO: SodistoreGrid — update configuration fields when defined
|
||||
|
|
|
|||
|
|
@ -16,5 +16,16 @@ public class Configuration
|
|||
public Single TimeChargeandDischargePower { get; set; }
|
||||
public Boolean ControlPermission { get; set; }
|
||||
|
||||
// Dynamic Pricing (under GridPriority) — strings for demo; engine parses when needed.
|
||||
public String? DynamicPricingMode { get; set; }
|
||||
public String? NetworkProvider { get; set; }
|
||||
public String? CurrentPrice { get; set; }
|
||||
public String? PriceToSell { get; set; }
|
||||
public String? PriceToBuy { get; set; }
|
||||
public String? TimeToSellFrom { get; set; }
|
||||
public String? TimeToSellTo { get; set; }
|
||||
public String? TimeToBuyFrom { get; set; }
|
||||
public String? TimeToBuyTo { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -639,6 +639,15 @@ internal static class Program
|
|||
status.Config.PvNumber = config.PvNumber;
|
||||
status.Config.ControlPermission = config.ControlPermission;
|
||||
|
||||
status.Config.DynamicPricingMode = config.DynamicPricingMode;
|
||||
status.Config.NetworkProvider = config.NetworkProvider;
|
||||
status.Config.CurrentPrice = config.CurrentPrice;
|
||||
status.Config.PriceToSell = config.PriceToSell;
|
||||
status.Config.PriceToBuy = config.PriceToBuy;
|
||||
status.Config.TimeToSellFrom = config.TimeToSellFrom;
|
||||
status.Config.TimeToSellTo = config.TimeToSellTo;
|
||||
status.Config.TimeToBuyFrom = config.TimeToBuyFrom;
|
||||
status.Config.TimeToBuyTo = config.TimeToBuyTo;
|
||||
}
|
||||
|
||||
private static async Task<Boolean> SaveModbusTcpFile(StatusRecord status)
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ public class Config
|
|||
//public required Decimal CheapPrice { get; set; }
|
||||
//public required Decimal HighPrice { get; set; }
|
||||
public required Double MinSoc { get; set; }
|
||||
public required Double GridSetPoint { get; set; }
|
||||
public required Double MaximumDischargingCurrent { get; set; }
|
||||
public required Double MaximumChargingCurrent { get; set; }
|
||||
public required OperatingPriority OperatingPriority { get; set; }
|
||||
public required Double GridSetPoint { get; set; }
|
||||
public required Double MaximumDischargingCurrent { get; set; }
|
||||
public required Double MaximumChargingCurrent { get; set; }
|
||||
public required OperatingPriority OperatingPriority { get; set; }
|
||||
public required Int16 BatteriesCount { get; set; }
|
||||
public required Int16 ClusterNumber { get; set; }
|
||||
public required Int16 PvNumber { get; set; }
|
||||
|
|
@ -34,7 +34,18 @@ public class Config
|
|||
public required DateTime StopTimeChargeandDischargeDayandTime { get; set; }
|
||||
|
||||
public required Single TimeChargeandDischargePower { get; set; }
|
||||
public required Boolean ControlPermission { get; set; }
|
||||
public required Boolean ControlPermission { get; set; }
|
||||
|
||||
// Dynamic Pricing (under GridPriority) — strings for demo; engine parses when needed.
|
||||
public String? DynamicPricingMode { get; set; }
|
||||
public String? NetworkProvider { get; set; }
|
||||
public String? CurrentPrice { get; set; }
|
||||
public String? PriceToSell { get; set; }
|
||||
public String? PriceToBuy { get; set; }
|
||||
public String? TimeToSellFrom { get; set; }
|
||||
public String? TimeToSellTo { get; set; }
|
||||
public String? TimeToBuyFrom { get; set; }
|
||||
public String? TimeToBuyTo { get; set; }
|
||||
|
||||
|
||||
public required S3Config? S3 { get; set; }
|
||||
|
|
|
|||
|
|
@ -715,6 +715,11 @@ export type ConfigurationValues = {
|
|||
currentPrice?: string;
|
||||
priceToSell?: string;
|
||||
priceToBuy?: string;
|
||||
// TOU time windows stored as "HH:mm" strings
|
||||
timeToSellFrom?: string;
|
||||
timeToSellTo?: string;
|
||||
timeToBuyFrom?: string;
|
||||
timeToBuyTo?: string;
|
||||
};
|
||||
//
|
||||
// export interface Pv {
|
||||
|
|
|
|||
|
|
@ -28,14 +28,13 @@ import { UserContext } from '../../../contexts/userContext';
|
|||
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
||||
import {
|
||||
INSTALLATION_PRESETS,
|
||||
buildSodistoreProPreset,
|
||||
getPresetsForDevice,
|
||||
PresetConfig
|
||||
} from '../Information/installationSetupUtils';
|
||||
import { LocalizationProvider } from '@mui/x-date-pickers';
|
||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||
import {DateTimePicker } from '@mui/x-date-pickers';
|
||||
import { DateTimePicker, TimePicker } from '@mui/x-date-pickers';
|
||||
import dayjs from 'dayjs';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
|
|
@ -70,7 +69,7 @@ function SodistoreHomeConfiguration(props: SodistoreHomeConfigurationProps) {
|
|||
const DynamicPricingOptions = ['Disabled', 'SpotPrice', 'Tou'] as const;
|
||||
const dynamicPricingLabelKey: Record<string, string> = {
|
||||
Disabled: 'dynamicPricingOff',
|
||||
SpotPrice: 'dynamicPricingOn',
|
||||
SpotPrice: 'dynamicPricingSpotPrice',
|
||||
Tou: 'dynamicPricingTou',
|
||||
};
|
||||
|
||||
|
|
@ -140,6 +139,10 @@ function SodistoreHomeConfiguration(props: SodistoreHomeConfigurationProps) {
|
|||
currentPrice: (props.values.Config as any).CurrentPrice?.toString() ?? '',
|
||||
priceToSell: (props.values.Config as any).PriceToSell?.toString() ?? '',
|
||||
priceToBuy: (props.values.Config as any).PriceToBuy?.toString() ?? '',
|
||||
timeToSellFrom: (props.values.Config as any).TimeToSellFrom ?? '',
|
||||
timeToSellTo: (props.values.Config as any).TimeToSellTo ?? '',
|
||||
timeToBuyFrom: (props.values.Config as any).TimeToBuyFrom ?? '',
|
||||
timeToBuyTo: (props.values.Config as any).TimeToBuyTo ?? '',
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -286,6 +289,10 @@ function SodistoreHomeConfiguration(props: SodistoreHomeConfigurationProps) {
|
|||
currentPrice: formValues.currentPrice,
|
||||
priceToSell: formValues.priceToSell,
|
||||
priceToBuy: formValues.priceToBuy,
|
||||
timeToSellFrom: formValues.timeToSellFrom,
|
||||
timeToSellTo: formValues.timeToSellTo,
|
||||
timeToBuyFrom: formValues.timeToBuyFrom,
|
||||
timeToBuyTo: formValues.timeToBuyTo,
|
||||
};
|
||||
|
||||
setLoading(true);
|
||||
|
|
@ -692,9 +699,9 @@ function SodistoreHomeConfiguration(props: SodistoreHomeConfigurationProps) {
|
|||
</>
|
||||
)}
|
||||
|
||||
{/* --- Sinexcel + GridPriority: Dynamic Pricing --- */}
|
||||
{/* --- Sinexcel + LoadPriority: Dynamic Pricing --- */}
|
||||
{device === 4 &&
|
||||
OperatingPriorityOptions[formValues.operatingPriority] === 'GridPriority' && (
|
||||
OperatingPriorityOptions[formValues.operatingPriority] === 'LoadPriority' && (
|
||||
<>
|
||||
<Typography variant="h6" sx={{ mt: 3, mb: 1 }}>
|
||||
<FormattedMessage id="dynamicPricing" defaultMessage="Dynamic Pricing" />
|
||||
|
|
@ -725,6 +732,59 @@ function SodistoreHomeConfiguration(props: SodistoreHomeConfigurationProps) {
|
|||
</FormControl>
|
||||
</div>
|
||||
|
||||
{formValues.dynamicPricingMode === 'Tou' && (
|
||||
<>
|
||||
{(() => {
|
||||
const renderTimeField = (
|
||||
labelId: string,
|
||||
key: 'timeToSellFrom' | 'timeToSellTo' | 'timeToBuyFrom' | 'timeToBuyTo'
|
||||
) => {
|
||||
const raw = formValues[key];
|
||||
const parsed = raw ? dayjs(raw, 'HH:mm') : null;
|
||||
return (
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<TimePicker
|
||||
ampm={false}
|
||||
label={intl.formatMessage({ id: labelId })}
|
||||
value={parsed && parsed.isValid() ? parsed : null}
|
||||
onChange={(newValue) => {
|
||||
setFormDirty(true);
|
||||
setFormValues((prev) => ({
|
||||
...prev,
|
||||
[key]: newValue ? newValue.format('HH:mm') : '',
|
||||
}));
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} sx={{ marginTop: 2, width: '100%' }} />
|
||||
)}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="subtitle2" sx={{ mt: 2, ml: 1 }}>
|
||||
<FormattedMessage id="timeToSell" defaultMessage="Time to Sell" />
|
||||
</Typography>
|
||||
<div style={{ display: 'flex', gap: 8, marginLeft: 8 }}>
|
||||
{renderTimeField('timeFrom', 'timeToSellFrom')}
|
||||
{renderTimeField('timeTo', 'timeToSellTo')}
|
||||
</div>
|
||||
|
||||
<Typography variant="subtitle2" sx={{ mt: 2, ml: 1 }}>
|
||||
<FormattedMessage id="timeToBuy" defaultMessage="Time to Buy" />
|
||||
</Typography>
|
||||
<div style={{ display: 'flex', gap: 8, marginLeft: 8 }}>
|
||||
{renderTimeField('timeFrom', 'timeToBuyFrom')}
|
||||
{renderTimeField('timeTo', 'timeToBuyTo')}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</>
|
||||
)}
|
||||
|
||||
{formValues.dynamicPricingMode === 'SpotPrice' && (
|
||||
<>
|
||||
<div style={{ marginBottom: '5px' }}>
|
||||
|
|
|
|||
|
|
@ -532,11 +532,15 @@
|
|||
"dynamicPricing": "Dynamische Preisgestaltung",
|
||||
"dynamicPricingMode": "Modus der dynamischen Preisgestaltung",
|
||||
"dynamicPricingOff": "Aus",
|
||||
"dynamicPricingOn": "Ein",
|
||||
"dynamicPricingSpotPrice": "Spot-Preis",
|
||||
"dynamicPricingTou": "TOU",
|
||||
"currentPrice": "Aktueller Preis",
|
||||
"priceToSell": "Verkaufspreis",
|
||||
"priceToBuy": "Kaufpreis",
|
||||
"timeToSell": "Verkaufszeit",
|
||||
"timeToBuy": "Kaufzeit",
|
||||
"timeFrom": "Von",
|
||||
"timeTo": "Bis",
|
||||
"networkProviderSetOnInformationTab": "Im Informations-Tab festlegen",
|
||||
"tourLanguageTitle": "Sprache",
|
||||
"tourLanguageContent": "Wählen Sie Ihre bevorzugte Sprache. Die Oberfläche unterstützt Englisch, Deutsch, Französisch und Italienisch.",
|
||||
|
|
|
|||
|
|
@ -280,11 +280,15 @@
|
|||
"dynamicPricing": "Dynamic Pricing",
|
||||
"dynamicPricingMode": "Dynamic Pricing Mode",
|
||||
"dynamicPricingOff": "Off",
|
||||
"dynamicPricingOn": "On",
|
||||
"dynamicPricingSpotPrice": "Spot Price",
|
||||
"dynamicPricingTou": "TOU",
|
||||
"currentPrice": "Current Price",
|
||||
"priceToSell": "Price to Sell",
|
||||
"priceToBuy": "Price to Buy",
|
||||
"timeToSell": "Time to Sell",
|
||||
"timeToBuy": "Time to Buy",
|
||||
"timeFrom": "From",
|
||||
"timeTo": "To",
|
||||
"networkProviderSetOnInformationTab": "Set on Information tab",
|
||||
"tourLanguageTitle": "Language",
|
||||
"tourLanguageContent": "Choose your preferred language. The interface supports English, German, French, and Italian.",
|
||||
|
|
|
|||
|
|
@ -532,11 +532,15 @@
|
|||
"dynamicPricing": "Tarification dynamique",
|
||||
"dynamicPricingMode": "Mode de tarification dynamique",
|
||||
"dynamicPricingOff": "Désactivé",
|
||||
"dynamicPricingOn": "Activé",
|
||||
"dynamicPricingSpotPrice": "Prix spot",
|
||||
"dynamicPricingTou": "TOU",
|
||||
"currentPrice": "Prix actuel",
|
||||
"priceToSell": "Prix de vente",
|
||||
"priceToBuy": "Prix d'achat",
|
||||
"timeToSell": "Heure de vente",
|
||||
"timeToBuy": "Heure d'achat",
|
||||
"timeFrom": "De",
|
||||
"timeTo": "À",
|
||||
"networkProviderSetOnInformationTab": "À définir dans l'onglet Informations",
|
||||
"tourLanguageTitle": "Langue",
|
||||
"tourLanguageContent": "Choisissez votre langue préférée. L'interface est disponible en anglais, allemand, français et italien.",
|
||||
|
|
|
|||
|
|
@ -532,11 +532,15 @@
|
|||
"dynamicPricing": "Prezzi dinamici",
|
||||
"dynamicPricingMode": "Modalità prezzi dinamici",
|
||||
"dynamicPricingOff": "Off",
|
||||
"dynamicPricingOn": "On",
|
||||
"dynamicPricingSpotPrice": "Prezzo spot",
|
||||
"dynamicPricingTou": "TOU",
|
||||
"currentPrice": "Prezzo attuale",
|
||||
"priceToSell": "Prezzo di vendita",
|
||||
"priceToBuy": "Prezzo di acquisto",
|
||||
"timeToSell": "Orario di vendita",
|
||||
"timeToBuy": "Orario di acquisto",
|
||||
"timeFrom": "Da",
|
||||
"timeTo": "A",
|
||||
"networkProviderSetOnInformationTab": "Imposta nella scheda Informazioni",
|
||||
"tourLanguageTitle": "Lingua",
|
||||
"tourLanguageContent": "Scegli la tua lingua preferita. L'interfaccia supporta inglese, tedesco, francese e italiano.",
|
||||
|
|
|
|||
Loading…
Reference in New Issue