- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
107 lines
3.3 KiB
Python
107 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Cariflex - Configure flex_context and flex_model for all 40 assets in FlexMeasures.
|
|
"""
|
|
import subprocess, json
|
|
|
|
def run_sql(query):
|
|
result = subprocess.run([
|
|
"docker", "exec", "flexmeasures-db", "psql", "-U", "flexmeasures", "-d", "flexmeasures",
|
|
"-t", "-c", query
|
|
], capture_output=True, text=True)
|
|
return result.stdout.strip()
|
|
|
|
# Flex context per asset type
|
|
FLEX_CONTEXTS = {
|
|
1: { # Panneau PV
|
|
"consumption-capacity": "0kW",
|
|
"production-capacity": "5kW",
|
|
"soc-min": "0kWh",
|
|
"soc-max": "0kWh"
|
|
},
|
|
2: { # Batterie
|
|
"consumption-capacity": "50kW",
|
|
"production-capacity": "50kW",
|
|
"soc-min": "10kWh",
|
|
"soc-max": "100kWh",
|
|
"charging-efficiency": "95%",
|
|
"discharging-efficiency": "95%"
|
|
},
|
|
3: { # Borne VE
|
|
"consumption-capacity": "22kW",
|
|
"production-capacity": "0kW",
|
|
"soc-min": "0kWh",
|
|
"soc-max": "0kWh"
|
|
},
|
|
4: { # Véhicule EV (V2G)
|
|
"consumption-capacity": "11kW",
|
|
"production-capacity": "11kW",
|
|
"soc-min": "15kWh",
|
|
"soc-max": "75kWh",
|
|
"charging-efficiency": "95%",
|
|
"discharging-efficiency": "95%"
|
|
}
|
|
}
|
|
|
|
# Flex model per asset type (storage-specific)
|
|
FLEX_MODELS = {
|
|
2: { # Batterie
|
|
"soc-at-start": "50kWh",
|
|
"soc-target": "80kWh",
|
|
"soc-min": "10kWh",
|
|
"soc-max": "100kWh",
|
|
"roundtrip-efficiency": "90%",
|
|
"storage-efficiency": "99%",
|
|
"power-capacity": "50kW"
|
|
},
|
|
4: { # EV V2G
|
|
"soc-at-start": "40kWh",
|
|
"soc-target": "60kWh",
|
|
"soc-min": "15kWh",
|
|
"soc-max": "75kWh",
|
|
"roundtrip-efficiency": "90%",
|
|
"storage-efficiency": "99%",
|
|
"power-capacity": "11kW"
|
|
}
|
|
}
|
|
|
|
print("=== Configuring flex_context and flex_model for Cariflex assets ===\n")
|
|
|
|
# Get assets by type
|
|
for type_id, type_name in [(1, "PV"), (2, "Battery"), (3, "EV Charger"), (4, "EV V2G")]:
|
|
assets = run_sql(f"SELECT id, name FROM generic_asset WHERE generic_asset_type_id = {type_id} ORDER BY id;")
|
|
flex_context = json.dumps(FLEX_CONTEXTS.get(type_id, {}))
|
|
flex_model = json.dumps(FLEX_MODELS.get(type_id, {}))
|
|
|
|
# Escape single quotes for SQL
|
|
flex_context_sql = flex_context.replace("'", "''")
|
|
flex_model_sql = flex_model.replace("'", "''")
|
|
|
|
# Update all assets of this type
|
|
result = run_sql(f"""
|
|
UPDATE generic_asset
|
|
SET flex_context = '{flex_context_sql}'::jsonb,
|
|
flex_model = '{flex_model_sql}'::jsonb
|
|
WHERE generic_asset_type_id = {type_id};
|
|
""")
|
|
|
|
count = len([l for l in assets.split('\n') if l.strip()])
|
|
print(f" ✅ {type_name}: {count} assets updated")
|
|
print(f" flex_context: {flex_context}")
|
|
if type_id in FLEX_MODELS:
|
|
print(f" flex_model: {flex_model}")
|
|
print()
|
|
|
|
# Verify
|
|
print("=== Verification ===")
|
|
for type_id, type_name in [(1, "PV"), (2, "Battery"), (3, "EV Charger"), (4, "EV V2G")]:
|
|
sample = run_sql(f"""
|
|
SELECT name, flex_context::text, flex_model::text
|
|
FROM generic_asset
|
|
WHERE generic_asset_type_id = {type_id}
|
|
LIMIT 1;
|
|
""")
|
|
print(f" {type_name}: {sample}")
|
|
|
|
print("\n✅ Flex context and model configured for all 40 assets!")
|