From 9e94e93f12a9d9718c9ba685bbb41662691fc5ad Mon Sep 17 00:00:00 2001 From: Taras Syvash Date: Sun, 26 Oct 2025 17:24:37 +0200 Subject: [PATCH] init commit --- .gitignore | 1 + README.md | 55 ++++++++++ __pycache__/database.cpython-314.pyc | Bin 0 -> 6825 bytes app.py | 147 +++++++++++++++++++++++++++ collector.py | 48 +++++++++ config.json | 29 ++++++ database.py | 108 ++++++++++++++++++++ templates/graphs.html | 90 ++++++++++++++++ templates/index.html | 127 +++++++++++++++++++++++ 9 files changed, 605 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 __pycache__/database.cpython-314.pyc create mode 100644 app.py create mode 100644 collector.py create mode 100644 config.json create mode 100644 database.py create mode 100644 templates/graphs.html create mode 100644 templates/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80ef064 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +temperature_history.db diff --git a/README.md b/README.md new file mode 100644 index 0000000..bd25bce --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# Монітор температури Raspberry Pi + +## Підготовка до запуску + +1. Встановіть необхідні залежності: +```bash +pip install flask paramiko psutil +``` + +2. Створіть файл конфігурації `config.json`: +```json +{ + "devices": [ + { + "host": "192.168.1.100", + "username": "pi", + "password": "raspberry" + } + ] +} +``` + +## Запуск додатку + +1. Запустіть колектор даних в окремому терміналі: +```bash +python collector.py +``` + +2. Запустіть Flask-додаток в іншому терміналі: +```bash +python app.py +``` + +3. Відкрийте веб-браузер та перейдіть за адресою: +``` +http://localhost:8080 +``` + +## Примітки + +- Переконайтеся, що всі Raspberry Pi доступні в мережі +- Перевірте правильність логіну та паролю в config.json +- За замовчуванням додаток буде доступний на порту 8080 +- Для доступу з інших пристроїв використовуйте IP-адресу комп'ютера замість localhost + +## Структура проекту + +``` +PI-SYSTEM-MONITOR/ +├── app.py # Основний Flask-додаток +├── config.json # Конфігурація підключень +└── templates/ + └── index.html # HTML шаблон +``` diff --git a/__pycache__/database.cpython-314.pyc b/__pycache__/database.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e5cfcf040487122d09456ee0435627d05925640 GIT binary patch literal 6825 zcmb`MTWlN06^3WIT#}L~S+Zo&mMw84M;9it6Bx&umX>&mzQUiTZ)1+0KII(3vv_K!0unimA01eQ*f6#UwEP?W4>^E4-`(4CkfB^ zh@3kzG6UxZpW%=}HXLGQ)=oB%cEYnZ!W(xQay?}u&uk?Q?kha?I}EBN7Lf%xepFDa zFpmidITFp;=JI?;aytO$5xD42h|KUrHayA6Y%@s_zKUmTB*B1dgN?`>UQjmiM##;4 zHP2~n7ATptQWbBOt3yPt;Vm$b8nrek98C*iM9zqU#}(BthZn~(ONiz64k(-?WA#a_ z)l!HAprtbH%vab6Prx~YH)xJchNt2QK{dydaXB2DggT=nB&I|QSW9?~t}b<7->4*r zQlA_VBa#$VPcN^+Rl)*foI5@(sS#SRx3Ma{C zGNHGSKbP1XrjCcFB2hUdo=~g2&qRf^98V=x zb0Rf89ZycHoFIxR(ZP!NC{!bQP#HnO8P`RrScA27(}En%`^L^&%HMo>EBcXs4B1Jt zWHeQ+|Gcr~+`#Jt@9unm-+TM6Ha^YN?WE%7y32ImLj}8v5Y&V_GgmEAg#(58u=-MV2 zws(5N42;K4yq}d5v7!1*+U=?8-KFU2W`{^W3a&I#=^r%^S6I&M&OBXMCr9OT=QUze6mw4NL1uZNr(v zrw_j}gzy=Bc~IH3@49vWQZ=b>{#El^8?UWv$Ntr?RiCx~nboV& zG8aF$E}@HWr3YZFr<^wDesXDljjNkow6wT7*u@SG%iXN&L9+N@hug|V@e$|=AAlAv z7w!*i#*lGUuyG-7Ww4E{53&8MuA}S({QQr23o%wuXCVljyfFlT;kg~=B0d3mmQ|5w zTmyM#Kpy&b)Jt{N^wI)S%JG2iLe9Za?+EP~=%u+oT|oDACsW6}dug}!4Wox{M|tX%HU(e`eS((uq7Gh4e2h*U}{O(s3M z@W4Xz!qXRLEBWzxl28kUM7 zQ#~0qXAIj(#&8g>dF(jP^|lmy_zj2QI#r|%+S6vYXU{Ebnf*hTRBoZnorD45X z3RqMts@U^-kiKiMNu!J8{u=tBA0_8QVl^wY3ROF!__*L>WFRQxu;%x>W#$Q<6qQoIDh=AZP)qZziof> z!FOuktUZ4`Yuk16Ue#MJja_XUx-@o?d3W=#pSxl2&)WOv-B<0q7aDHZ_bT?im&USf zLrZ33QyqxvO7WamzTezxARBjoquO?TqqYs*{jzf156%`?rDfkW>;C%-LwUOY$ zQIzvddV3)pa3v!u1Pk3t+e*S>*!}^`MA5AG5t4z&Gq$ECVvl0k{B1x{nUb+J+Ocyo{D8@JA4- zJQGRM*;bm58FVHBfSeSBB#kD7ND?G?CSAIY*J?9q?5%q$i0Mk0iug`6n2JBbQn|nu z?O2CzNW*54rw&sNpylioccY~yr%|eDVmhy;8}ow-!=S>sRf43pmy>b@6Wr~UvXCJ$ z>;4bKRGK{(pHmKwU9%p!X{|5c71+FEe%HK1*?UCUG=AOs#P?IzD{W`4t*%|`UAxKR z?izOodzo!vu4-%_U1MJ=|=Ep8%Mza7pB_;?8|C z0?{k1R)@n!Q?X0}%hquCSSFIlx2y}p4+x?pC*nyVnF@zR+(OKSSd46<1GBxD9e_;T z5Dr7MmgCWIM26TriK+#BHiW~`1pKxTi$~?CkVu5X4o0mlsf2DQ!5`BWQzA|WEkoK$ zC<^ZW6yE6_gMqW%vRJtFx0;%{)>{v+=UVUdv~aCo@2-ba0-1<=m|9l{CnBk|m7j ? + ORDER BY timestamp ASC + ''', (host, time_threshold)) + + results = c.fetchall() + return { + 'gpu': [r['gpu_temp'] for r in results], + 'cpu': [r['cpu_temp'] for r in results], + 'timestamps': [r['timestamp'].split(' ')[1] for r in results] # Беремо тільки час + } + except Exception as e: + logging.error(f"Failed to retrieve history: {e}") + raise + finally: + if 'conn' in locals(): + conn.close() + + def cleanup_old_records(self, minutes=30): + """Видалення старих записів""" + try: + conn = self.get_connection() + c = conn.cursor() + + time_threshold = (datetime.now() - timedelta(minutes=minutes)).strftime('%Y-%m-%d %H:%M:%S') + + c.execute('DELETE FROM temperatures WHERE timestamp < ?', (time_threshold,)) + conn.commit() + logging.info(f"Old records older than {minutes} minutes have been cleaned up") + except Exception as e: + logging.error(f"Failed to cleanup old records: {e}") + raise + finally: + if 'conn' in locals(): + conn.close() diff --git a/templates/graphs.html b/templates/graphs.html new file mode 100644 index 0000000..dd35083 --- /dev/null +++ b/templates/graphs.html @@ -0,0 +1,90 @@ + + + + + + Графіки температур - Raspberry Pi + + + + + +
+
+

Графіки температур за останні 30 хвилин

+ ← Повернутися до моніторингу +
+ +
+ {% for device in devices %} +
+
+
+
{{ device.hostname }} ({{ device.host }})
+
+ +
+
+
+
+ {% endfor %} +
+
+ + + + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..6f3411c --- /dev/null +++ b/templates/index.html @@ -0,0 +1,127 @@ + + + + + + Монітор температури Raspberry Pi + + + + + + +
+
+

Температура системи

+ Переглянути детальні графіки → +
+ +
+
+
+ Оновлено: {{ current_time }} + (автоматичне оновлення кожні 10 секунд) +
+ +
+ + + + + + + + + + + + + + {% for temp in temperatures %} + + + + + + + + + + {% endfor %} + +
IP-адресаHostnameТемпература GPUТемпература CPUГрафік GPUГрафік CPUСтатус
{{ temp.name }}{{ temp.hostname }}{% if temp.value is string %}{{ temp.value }}{% else %}{{ temp.value }}°C{% endif %}{% if temp.cpu is string %}{{ temp.cpu }}{% else %}{{ temp.cpu }}°C{% endif %} + {{ temp.status }} +
+
+
+
+
+ + + + +