Skip to content

Commit 2746aa8

Browse files
authored
Merge pull request #13 from extinctCoder/sas-branch-5
feat(config): clean up defaults, add logging, docker artifacts
2 parents f1a533b + 2b95123 commit 2746aa8

9 files changed

Lines changed: 88 additions & 27 deletions

File tree

.env.sample

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
MOSQUITTO_USER = extinctcoder
2-
MOSQUITTO_PASSWD = Mosquitto123456#
1+
############################################################################
2+
# Power Station Simulator Configuration
3+
#
4+
# This file contains configuration parameters for the power station simulator.
5+
# It defines MQTT connection settings, station identification, location, and
6+
# publishing intervals for simulation data.
7+
############################################################################
38

4-
PS_001_POWER_STATION_ID=PS_001
5-
PS_002_POWER_STATION_ID=PS_002
9+
PS_001_MQTT_PORT=1883
10+
PS_001_MQTT_HOST="mosquitto"
11+
PS_001_MQTT_USERNAME="extinctcoder"
12+
PS_001_MQTT_PASSWORD="Mosquitto123456#"
13+
PS_001_MQTT_TOPIC_PREFIX="smartgrid/powerstation"
614

7-
PS_001_LOCATION="Dhaka, Bangladesh"
8-
PS_002_LOCATION="Chittagong, Bangladesh"
15+
PS_001_ENABLE_WEBSOCKET=False
916

17+
PS_001_CAPACITY_KW=2600
18+
PS_001_POWER_STATION_ID="PS_001"
1019
PS_001_PUBLISH_INTERVAL_SECONDS=1
11-
PS_002_PUBLISH_INTERVAL_SECONDS=4
20+
PS_001_LOCATION="Saidpur, Bangladesh"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ docker/home_assistant/**
66
# python git ignores
77
venv
88

9+
.env
910

1011
**.pyc
1112
__pycache__

codebook.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@ words = [
1818
"behaviour",
1919
"sexualized",
2020
"sublicense",
21-
"NONINFRINGEMENT"
21+
"NONINFRINGEMENT",
22+
"healthcheck",
23+
"Saidpur"
2224
]

docker-compose.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,35 @@ services:
3535

3636
environment:
3737
- TZ=Asia/Dhaka
38+
39+
healthcheck:
40+
test: ["CMD", "nc", "-z", "localhost", "1883"]
41+
interval: 10s
42+
timeout: 5s
43+
retries: 5
44+
start_period: 1s
45+
46+
powerstation_simulator:
47+
image: ps_sim:dev
48+
build:
49+
context: .
50+
dockerfile: ps_sim.dockerfile
51+
52+
container_name: powerstation_simulator
53+
hostname: powerstation_simulator
54+
55+
restart: unless-stopped
56+
57+
depends_on:
58+
mosquitto:
59+
condition: service_healthy
60+
61+
env_file:
62+
- .env.sample
63+
64+
environment:
65+
- TZ=Asia/Dhaka
66+
- STATION_PREFIX=PS_001
67+
68+
volumes:
69+
- ./src/powerstation_simulator:/app/src

ps_sim.dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Use minimal Python 3.13 base image (Alpine = very small footprint)
2+
FROM python:3.13-alpine
3+
4+
# Set working directory inside the container
5+
WORKDIR /app
6+
7+
# Copy requirements file from host and rename it to requirements.txt
8+
COPY requirements.ps_sim.txt requirements.txt
9+
10+
# Install Python dependencies without caching to keep image small
11+
RUN pip install --no-cache-dir --root-user-action=ignore -r requirements.txt
12+
13+
# Copy application source code into the container
14+
COPY src/powerstation_simulator/ src/
15+
16+
# Default command: run the main Python entrypoint
17+
CMD ["sh", "-c", "python src/main.py"]
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
jsonb
21
pydantic
32
paho-mqtt
43
pydantic-settings

src/powerstation_simulator/config.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
from os import getenv
22
from typing import Annotated
33

4+
from logger import getLogger
45
from pydantic import Field
56
from pydantic_settings import BaseSettings, SettingsConfigDict
67

8+
logger = getLogger(__name__)
9+
710

811
class AppConfig(BaseSettings):
912
"""
@@ -25,25 +28,21 @@ class AppConfig(BaseSettings):
2528
)
2629

2730
# Metadata (static info)
28-
POWER_STATION_ID: Annotated[str, Field(alias="POWER_STATION_ID")] = "ps-001"
29-
LOCATION: Annotated[str, Field(alias="LOCATION")] = "Dhaka, Bangladesh"
30-
CAPACITY_KW: Annotated[int, Field(alias="CAPACITY_KW")] = 1000
31+
POWER_STATION_ID: Annotated[str, Field()] = "PS_001"
32+
LOCATION: Annotated[str, Field()] = "Dhaka, Bangladesh"
33+
CAPACITY_KW: Annotated[int, Field()] = 1000
3134

3235
# MQTT broker config
33-
MQTT_HOST: Annotated[str, Field(alias="MQTT_HOST")] = "localhost"
34-
MQTT_PORT: Annotated[int, Field(alias="MQTT_PORT")] = 1883
35-
MQTT_USERNAME: Annotated[str, Field(alias="MQTT_USERNAME")] = "extinctcoder"
36-
MQTT_PASSWORD: Annotated[str, Field(alias="MQTT_PASSWORD")] = "Mosquitto123456#"
37-
MQTT_TOPIC_PREFIX: Annotated[str, Field(alias="MQTT_TOPIC_PREFIX")] = (
38-
"smartgrid/powerstation"
39-
)
36+
MQTT_HOST: Annotated[str, Field()] = "127.0.0.1"
37+
MQTT_PORT: Annotated[int, Field()] = 1883
38+
MQTT_USERNAME: Annotated[str, Field()] = "extinctcoder"
39+
MQTT_PASSWORD: Annotated[str, Field()] = "Mosquitto123456#"
40+
MQTT_TOPIC_PREFIX: Annotated[str, Field()] = "smartgrid/powerstation"
4041

41-
ENABLE_WEBSOCKET: Annotated[bool, Field(alias="ENABLE_WEBSOCKET")] = False
42+
ENABLE_WEBSOCKET: Annotated[bool, Field()] = False
4243

4344
# Simulator settings
44-
PUBLISH_INTERVAL_SECONDS: Annotated[
45-
int, Field(alias="PUBLISH_INTERVAL_SECONDS")
46-
] = 2
45+
PUBLISH_INTERVAL_SECONDS: Annotated[int, Field()] = 1
4746

4847
STATUS_PUBLISH_INTERVAL_SECONDS: int = PUBLISH_INTERVAL_SECONDS * 2
4948
METADATA_PUBLISH_INTERVAL_SECONDS: int = PUBLISH_INTERVAL_SECONDS * 5
@@ -56,6 +55,8 @@ def load_power_station_configs(station_prefix: str | None = None) -> AppConfig:
5655
"""
5756
station_prefix = station_prefix or getenv("STATION_PREFIX")
5857

58+
logger.info(f"Simple Power Station SIMULATOR serving station : {station_prefix}")
59+
5960
if not station_prefix:
6061
return AppConfig() # fallback to default or global settings
6162

src/powerstation_simulator/main.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ def main() -> None:
6363
args = parser.parse_args()
6464

6565
print(ps_banner)
66-
logger.info(
67-
f"Simple Power Station SIMULATOR serving station : {args.station_prefix}"
68-
)
66+
6967
app_config: AppConfig = load_power_station_configs(
7068
station_prefix=args.station_prefix
7169
)

src/powerstation_simulator/mqtt_client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from json import dumps
2+
from random import choices
3+
from string import ascii_letters, digits
24
from typing import Any
35

46
from config import AppConfig
@@ -41,7 +43,7 @@ def __init__(
4143
self.connected: bool = False
4244

4345
self.client: mqtt_client.Client = mqtt_client.Client(
44-
client_id=client_id,
46+
client_id=f"{client_id}_".join(choices(ascii_letters + digits, k=6)),
4547
transport="websockets" if enable_websocket else "tcp",
4648
)
4749
if username and password:

0 commit comments

Comments
 (0)