Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added practicedocker/imgs/screen1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added practicedocker/imgs/screen2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added practicedocker/imgs/screen3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added practicedocker/imgs/screen4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added practicedocker/imgs/screen5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions practicedocker/linux_a/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
services:
temp_1:
image: rodjonn/kulakov-sensor-simulator:latest
container_name: sensor_temp_1
environment:
- SIM_TYPE=temperature
- SIM_NAME=temp_1
- SIM_HOST=mosquitto
- SIM_PORT=1883
- SIM_PERIOD=2
networks:
- iot_network
restart: unless-stopped

temp_2:
image: rodjonn/kulakov-sensor-simulator:latest
container_name: sensor_temp_2
environment:
- SIM_TYPE=temperature
- SIM_NAME=temp_2
- SIM_HOST=mosquitto
- SIM_PORT=1883
- SIM_PERIOD=3
networks:
- iot_network
restart: unless-stopped

pressure_1:
image: rodjonn/kulakov-sensor-simulator:latest
container_name: sensor_pressure_1
environment:
- SIM_TYPE=pressure
- SIM_NAME=pressure_1
- SIM_HOST=mosquitto
- SIM_PORT=1883
- SIM_PERIOD=5
networks:
- iot_network
restart: unless-stopped

current_1:
image: rodjonn/kulakov-sensor-simulator:latest
container_name: sensor_current_1
environment:
- SIM_TYPE=current
- SIM_NAME=current_1
- SIM_HOST=mosquitto
- SIM_PORT=1883
- SIM_PERIOD=2
networks:
- iot_network
restart: unless-stopped

humidity_1:
image: rodjonn/kulakov-sensor-simulator:latest
container_name: sensor_humidity_1
environment:
- SIM_TYPE=humidity
- SIM_NAME=humidity_1
- SIM_HOST=mosquitto
- SIM_PORT=1883
- SIM_PERIOD=4
networks:
- iot_network
restart: unless-stopped

humidity_2:
image: rodjonn/kulakov-sensor-simulator:latest
container_name: sensor_humidity_2
environment:
- SIM_TYPE=humidity
- SIM_NAME=humidity_2
- SIM_HOST=mosquitto
- SIM_PORT=1883
- SIM_PERIOD=6
networks:
- iot_network
restart: unless-stopped

networks:
iot_network:
external: true
6 changes: 6 additions & 0 deletions practicedocker/linux_a/simulator/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM python:3.12-alpine3.19
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]
49 changes: 49 additions & 0 deletions practicedocker/linux_a/simulator/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import json
import os
import time

import paho.mqtt.client as mqtt

from sensor import SENSOR_TYPES

BROKER_HOST = os.getenv("SIM_HOST", "mosquitto")
BROKER_PORT = int(os.getenv("SIM_PORT", "1883"))
CLIENT_NAME = os.getenv("SIM_NAME", "sensor_1")
SIM_PERIOD = float(os.getenv("SIM_PERIOD", "2.0"))
SIM_TYPE = os.getenv("SIM_TYPE", "temperature")

sensor_class = SENSOR_TYPES.get(SIM_TYPE, SENSOR_TYPES["temperature"])
sensor = sensor_class(CLIENT_NAME)
topic = f"sensors/{sensor.type}/{CLIENT_NAME}"


def on_publish(client, userdata, mid):
print(f"[{CLIENT_NAME}] published mid={mid} -> {topic}", flush=True)


def connect_with_retry(client, host, port, retries=15, delay=3):
for attempt in range(1, retries + 1):
try:
client.connect(host, port, keepalive=60)
print(f"[{CLIENT_NAME}] Connected to {host}:{port}", flush=True)
return
except Exception as exc:
print(f"[{CLIENT_NAME}] Attempt {attempt}/{retries} failed: {exc}. Retry in {delay}s...", flush=True)
time.sleep(delay)
raise RuntimeError(f"Could not connect to {host}:{port} after {retries} attempts")


client = mqtt.Client(client_id=CLIENT_NAME)
client.on_publish = on_publish

connect_with_retry(client, BROKER_HOST, BROKER_PORT)
client.loop_start()

print(f"[{CLIENT_NAME}] Sensor type={SIM_TYPE}, topic={topic}, period={SIM_PERIOD}s", flush=True)

while True:
data = sensor.read()
payload = json.dumps(data)
client.publish(topic, payload, qos=1)
print(f"[{CLIENT_NAME}] {payload}", flush=True)
time.sleep(SIM_PERIOD)
1 change: 1 addition & 0 deletions practicedocker/linux_a/simulator/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
paho-mqtt==1.6.1
80 changes: 80 additions & 0 deletions practicedocker/linux_a/simulator/sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import random
import time
from abc import ABC, abstractmethod


class Sensor(ABC):
unit: str = ""

def __init__(self, name: str):
self.name = name
self.type = self.__class__.__name__.replace("Sensor", "").lower()

@abstractmethod
def generate(self) -> float:
pass

def read(self) -> dict:
return {
"sensor_id": self.name,
"type": self.type,
"value": round(self.generate(), 2),
"unit": self.unit,
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S"),
}


class TemperatureSensor(Sensor):
unit = "C"

def __init__(self, name: str):
super().__init__(name)
self._value = 20.0

def generate(self) -> float:
self._value += random.uniform(-0.5, 0.5)
return max(-10.0, min(50.0, self._value))


class PressureSensor(Sensor):
unit = "hPa"

def __init__(self, name: str):
super().__init__(name)
self._value = 1013.25

def generate(self) -> float:
self._value += random.uniform(-1.0, 1.0)
return max(950.0, min(1080.0, self._value))


class CurrentSensor(Sensor):
unit = "A"

def __init__(self, name: str):
super().__init__(name)
self._value = 5.0

def generate(self) -> float:
self._value += random.uniform(-0.2, 0.2)
return max(0.0, min(20.0, self._value))


class HumiditySensor(Sensor):
unit = "%"

def __init__(self, name: str):
super().__init__(name)
self._value = 50.0

def generate(self) -> float:
self._value += random.uniform(-1.0, 1.0)
return max(0.0, min(100.0, self._value))


SENSOR_TYPES = {
"temperature": TemperatureSensor,
"pressure": PressureSensor,
"current": CurrentSensor,
"humidity": HumiditySensor,
}
15 changes: 15 additions & 0 deletions practicedocker/linux_b/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
services:
mosquitto:
image: eclipse-mosquitto:2.0
container_name: mosquitto
ports:
- "1883:1883"
volumes:
- ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
networks:
- iot_network
restart: unless-stopped

networks:
iot_network:
external: true
2 changes: 2 additions & 0 deletions practicedocker/linux_b/mosquitto/mosquitto.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
listener 1883
allow_anonymous true
50 changes: 50 additions & 0 deletions practicedocker/linux_c/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
services:
influxdb:
image: influxdb:1.8
container_name: influxdb
ports:
- "8086:8086"
environment:
- INFLUXDB_DB=sensors
- INFLUXDB_HTTP_AUTH_ENABLED=false
volumes:
- influxdb_data:/var/lib/influxdb
networks:
- iot_network
restart: unless-stopped

telegraf:
image: telegraf:1.28
container_name: telegraf
volumes:
- ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro
depends_on:
- influxdb
networks:
- iot_network
restart: unless-stopped

grafana:
image: grafana/grafana:10.2.0
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_SECURITY_ADMIN_USER=admin
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
depends_on:
- influxdb
networks:
- iot_network
restart: unless-stopped

volumes:
influxdb_data:
grafana_data:

networks:
iot_network:
external: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: 1

datasources:
- name: InfluxDB
type: influxdb
url: http://influxdb:8086
database: sensors
isDefault: true
access: proxy
19 changes: 19 additions & 0 deletions practicedocker/linux_c/telegraf/telegraf.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[agent]
interval = "5s"
flush_interval = "5s"
hostname = "telegraf"

[[inputs.mqtt_consumer]]
servers = ["tcp://mosquitto:1883"]
topics = ["sensors/#"]
qos = 1
data_format = "json"
json_name_key = "type"
tag_keys = ["sensor_id", "type", "unit"]
json_time_key = "timestamp"
json_time_format = "2006-01-02T15:04:05"

[[outputs.influxdb]]
urls = ["http://influxdb:8086"]
database = "sensors"
skip_database_creation = false
Loading