в принципе это по реализации должно быть на уровне "сойдет га троечку", НО оказалось довольно трудоемко, учитывая что за модуль с API компания хочет покупку дополнительной лицензии, и на данный момент человек вручную с портала загружает эти данные, сама структура реализована на java контейнерах, и я понимаю что каждый пишет как умеет, но как потом с этим работать??? онлайн данные динамически прыгают через вебсокет и куча других "интересных" реализаций и вещей, и я осознанно решил решить свою проблему подходом неправильного "говнокода".
c# & etc
ищу удаленную работу, немного пишу на Php, C#, использую MySQL, базово применяю MS-SQL, прикручиваю к php Ajax, обслуживаю пару машин с Linux (программировал на Delphi, начальный уровень C++, администрировал - знаю что такое bash) ( I search job, Basic level English)
среда, 24 сентября 2025 г.
автоматизация получения отчетов с ZKBio CVAccess
среда, 17 сентября 2025 г.
ручная сортировка ошибок распознавания yolov8 с подготовкой наборов данных для до обучения модели
Модуль в составе системы распознавания объектов с фото для сортировки и отправки их по определенным критериям на почту и мессенджеры.
yolov8_tools
благодаря ограничениям аппаратного и программного обеспечения регистраторов, появилась необходимость пользоваться сторонней моделью распознавания объектов, но из-за недостаточного качества распознания, ручной контроль ошибок спровоцировал начать до обучение модели под конкретный объект и задачу.
16.09.2025 Проедено до обучение модели результатами работы этой оснастки, и начато тестирование до обученной модели.
понедельник, 1 сентября 2025 г.
простая реализация бэкапа небольшой папки в системе Linux на bash
Реализуется:
1. Получение бэкапа по почте, для отправки настроен msmtp
2. Создание, с исключением файлов по маске, исключения хранятся в отдельном файле
3. Создание архива с архивированием и шифрованием имен, один из серверов отказался пересылать вложение в котом был архив с запакованным js файлом :(
4. Если общий размер папки не изменился, то архивирования и отправки по почте не будет.
скажем так, информация что отправляется очень критичная!!!!
================ backup.bash
#!/bin/bash # --- Настройки --- BACKUP_DIR="/opt/datas" #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FINAL_ARCHIVE_NAME="backup_$(date +%Y-%m-%d).7z" TAR_ARCHIVE_NAME="temp_backup.tar.gz" EXCLUDE_FILE="./exclude.txt" ARCHIVE_PASSWORD="pass" RECIPIENT_EMAIL="email@mailserver" EMAIL_SUBJECT="Резервная копия от $(date +%Y-%m-%d)" EMAIL_BODY="Здравствуйте! Прикрепляю к письму резервную копию Tralalal. Архив защищен паролем. С уважением, Ваш скрипт бэкапа." # Файл для хранения размера последнего бэкапа LAST_SIZE_FILE="/tmp/backup_size.txt" # --- Логика --- # 1. Создание tar.gz архива if [ -f "$EXCLUDE_FILE" ]; then echo "Файл исключений $EXCLUDE_FILE найден. Создаем tar.gz архив с исключениями." tar -czvf "$TAR_ARCHIVE_NAME" -C "$BACKUP_DIR" --exclude-from="$EXCLUDE_FILE" . else echo "Файл исключений $EXCLUDE_FILE не найден. Создаем полный tar.gz бэкап." tar -czvf "$TAR_ARCHIVE_NAME" -C "$BACKUP_DIR" . fi if [ $? -ne 0 ]; then echo "Ошибка: Не удалось создать tar.gz архив. Процесс прерван." exit 1 fi # 2. Создание 7z архива echo "Сжимаем tar.gz архив в 7z с паролем и шифрованием имён файлов..." 7z a -p"$ARCHIVE_PASSWORD" -mhe=on "$FINAL_ARCHIVE_NAME" "$TAR_ARCHIVE_NAME" if [ $? -ne 0 ]; then echo "Ошибка: Не удалось создать 7z архив. Процесс прерван." rm "$TAR_ARCHIVE_NAME" exit 1 fi # 3. Проверка размера # Получаем размер нового 7z-архива в байтах CURRENT_SIZE=$(stat -c%s "$FINAL_ARCHIVE_NAME") if [ -f "$LAST_SIZE_FILE" ]; then LAST_SIZE=$(cat "$LAST_SIZE_FILE") else LAST_SIZE=0 fi if [ "$CURRENT_SIZE" == "$LAST_SIZE" ]; then echo "Размер архива не изменился. Отправка письма не требуется." rm "$TAR_ARCHIVE_NAME" rm "$FINAL_ARCHIVE_NAME" exit 0 fi echo "Размер архива изменился. Отправляем письмо." echo "$CURRENT_SIZE" > "$LAST_SIZE_FILE" # 4. Отправка по почте echo "Отправка архива по электронной почте на адрес $RECIPIENT_EMAIL..." ( echo -e "Subject: =?UTF-8?B?$(echo -n "$EMAIL_SUBJECT" | base64)?=\nMIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"BOUNDARY\"\n\n--BOUNDARY\nContent-Type: text/plain; charset=utf-8\n\n$EMAIL_BODY\n\n--BOUNDARY\nContent-Type: application/x-7z-compressed; name=\"$FINAL_ARCHIVE_NAME\"\nContent-Disposition: attachment; filename=\"$FINAL_ARCHIVE_NAME\"\nContent-Transfer-Encoding: base64\n\n$(base64 "$FINAL_ARCHIVE_NAME")\n--BOUNDARY--\n" ) | msmtp -a default -t "$RECIPIENT_EMAIL" if [ $? -ne 0 ]; then echo "Ошибка: Не удалось отправить письмо." exit 1 fi # 5. Очистка rm "$TAR_ARCHIVE_NAME" rm "$FINAL_ARCHIVE_NAME" echo "Резервное копирование завершено."
=======================
======= exclude.txt
*.tmp
*.log
*.log.*
*sessions*
*token*
===============
на github
четверг, 28 августа 2025 г.
сортировка фото, полученных с камер с использованием yolov8
Задача/необходимость:
для отслеживания движения на определенной зоне ставится детектор движения либо пересечения на изображении, НО коты-собаки, движения тени от листьев и просто ветер дает очень много лишнего "мусора", а нас волнуют авто и люди.
Вот и настало время компьютерного зрения с распознаванием объектов на фото.
Есть еще серьезный недостаток у камер, вендора Hikvision (возможно это мое устаревшее оборудование, НО мы еще поборемся), присылается на почту 3 фото, в зависимости от скорости пересечения некоторые из них не содержат интересующую информацию.
и большой + , получение полезной информации в чат Telegram, а позже реализация для Signal.
1. Данные получаем с почтового ящика.
2. Сравниваем фото из одного письма, если они отличаются на 2% то считаем их уникальными. (2% может и больше) и копируем в папку для распознавания.
3. Обрабатываем фото, поиском на нем объектов (перечень возможных), указанных в конфиге для конкретной камеры, если объекты найдены, копируем фото в отдельную папку и отсылаем его на почту/мессенджер, в ином случае переносим фото в папку ошибок1.
4. Вручную просмотрщиком обрабатываем папку ошибок1 удаляя фото без объектов и копируем фото с объектами для обучения модели в папку обучение1. (работа на ошибками)
5. Отдельным редактором делаем обозначения с описанием на фото обучение1.
6. Обучаем модель.
28.08.2025 - Пункты 1-2-3-4 реализованы, чатик с фото читаем, проводим тестирование и доработки.
12.09.2025 - Реализованы получение и отправка почты с разных адресов, выявлены ошибки по почте. Анонс: будет реализация с чатом WhatsApp.
среда, 20 августа 2025 г.
контроль атрибутов SMART диска в Linux, с передачей их изменения в телеграм
идея контролировать атрибуты винчестера в автоматическом порядке, при этом не создавая лишней нагрузки на файловую систему, значит: запись только если поменялись критические значения, некритические есть в файле для конкретного винчестера, учитывая что производители могут быть разными как и атрибуты у моделей
помогали несколько движков ИИ, не с первого далеко раза
периоды запуска реализованы через cron
заморачиваться с передачей названия диска в строке не стал
вероятно этот велосипед умрет с этой системой
реализация дополнится отсылкой почты админу
в телеграмме ньюанс насчет перевода на новые строки, меня не раздражает, даже некий юни- шарм
=========== smart_sda.bash
DISK="/dev/sda" NON_CRITICAL_FILE="/opt/smart/smart_non_critical_sda.txt" # Load configuration from external file CONFIG_FILE="/opt/smart/smart_v2.conf" if [ ! -f "$CONFIG_FILE" ]; then echo "Configuration file not found at $CONFIG_FILE. Please create it." >&2 exit 1 fi source "$CONFIG_FILE" # Generate file paths based on disk name DISK_NAME=$(basename "$DISK") # e.g., "sda" from "/dev/sda"
LOG_FILE="/dev/null" # Override log file to /dev/null
STATE_FILE="$BASE_DATA_DIR/smart_state_${DISK_NAME}.txt" DISK_INFO_FILE="$BASE_DATA_DIR/smart_disk_info_${DISK_NAME}.txt" # Ensure base directories exist mkdir -p "$BASE_DATA_DIR" 2>/dev/null # Ensure smartctl is installed if ! command -v "$SMARTCTL" &> /dev/null; then echo "smartctl not found. Please install smartmontools." >> "$LOG_FILE" exit 1 fi # Ensure non-critical attributes file exists if [ ! -f "$NON_CRITICAL_FILE" ]; then echo "Non-critical attributes file not found at $NON_CRITICAL_FILE" >> "$LOG_FILE" exit 1 fi # Read non-critical attributes into an array, extracting only the first field (number) mapfile -t NON_CRITICAL < <(grep -v '^\s*#' "$NON_CRITICAL_FILE" | grep -v '^\s*$' | awk '{print $1}') # Function to check if attribute is non-critical is_non_critical() { local attr_id=$1 for nc in "${NON_CRITICAL[@]}"; do if [ "$nc" == "$attr_id" ]; then return 0 fi done return 1 } # Function to get SMART attributes get_smart_attributes() { local output output=$("$SMARTCTL" -n standby -A "$DISK" 2>&1) if [ $? -ne 0 ]; then echo "Error executing smartctl -A on $DISK: $output" >> "$LOG_FILE" exit 1 fi echo "$output" | awk '/^[ 0-9]/ { print $1, $2, $10 }' } # Function to get disk info (name and serial number) - handles multi-word models get_disk_info() { local output output=$("$SMARTCTL" -i "$DISK" 2>&1) if [ $? -ne 0 ]; then echo "Error executing smartctl -i on $DISK: $output" >> "$LOG_FILE" exit 1 fi echo "$output" | awk ' /Device Model/ { out = "Device Model: "; for (i=3; i<=NF; i++) out = out $i (i<NF ? " " : ""); print out } /Serial Number/ { out = "Serial Number: "; for (i=3; i<=NF; i++) out = out $i (i<NF ? " " : ""); print out } ' } # Save disk info if file doesn't exist if [ ! -f "$DISK_INFO_FILE" ]; then get_disk_info > "$DISK_INFO_FILE" fi # Main logic timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] Checking SMART attributes for $DISK" >> "$LOG_FILE" # Get current SMART data current_data=$(get_smart_attributes) if [ -z "$current_data" ]; then echo "[$timestamp] No SMART data retrieved for $DISK." >> "$LOG_FILE" exit 0 fi # Flag to track if changes were found changes_detected=false telegram_message="" # Check if previous data exists if [ -f "$STATE_FILE" ]; then previous_data=$(cat "$STATE_FILE") # Compare with previous data while IFS= read -r prev_line; do prev_id=$(echo "$prev_line" | awk '{print $1}') prev_name=$(echo "$prev_line" | awk '{print $2}') prev_value=$(echo "$prev_line" | awk '{print $3}') # Find matching line in current data current_line=$(echo "$current_data" | grep "^$prev_id ") if [ -n "$current_line" ]; then current_value=$(echo "$current_line" | awk '{print $3}') # Check if value changed and attribute is not non-critical if [ "$prev_value" != "$current_value" ] && ! is_non_critical "$prev_id"; then echo "[$timestamp] Attribute $prev_id ($prev_name) changed: $prev_value -> $current_value" >> "$LOG_FILE" changes_detected=true telegram_message+="$prev_id ($prev_name): $prev_value -> $current_value\n" fi fi done <<< "$previous_data" fi # Save current data as new state only if changes in critical attributes were detected or no previous state exists if [ "$changes_detected" = true ] || [ ! -f "$STATE_FILE" ]; then echo "$current_data" > "$STATE_FILE" fi # Send Telegram notification if changes were detected if [ "$changes_detected" = true ]; then disk_info=$(cat "$DISK_INFO_FILE") full_message="SMART Changes detected on $DISK at $timestamp\n$disk_info\nChanges:\n$telegram_message" curl_response=$(curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \ -d chat_id="$TELEGRAM_CHAT_ID" \ -d text="$full_message" 2>&1) if [ $? -ne 0 ]; then echo "[$timestamp] Error sending Telegram notification for $DISK: $curl_response" >> "$LOG_FILE" else echo "[$timestamp] Telegram notification sent for $DISK" >> "$LOG_FILE" fi fi======== smart_v2.conf ====
среда, 16 июля 2025 г.
Mikrotik. ROS. Мониторинг состояния хостов по icmp.
задача по мониторингу состояния хостов в сети древняя, у меня было несколько реализаций, какую-то реализацию делал некий Влад (судя по коду может и не один), но собравший с остатками здравомыслия пришел я к следующему проекту:
1. Перечень хостов и их названий хранится в файле.
2. Мы отслеживаем отключение либо включение хоста в сети (по протоколу icmp)
3. Сообщения "уходят" в телеграмм, так как задач несколько, с ним мы работаем на модульном уровне, как в результат сложилось - используем глобальную переменную для сообщения, а в теле вызываем скрипт.
4. Периодически проверяем состояние и работоспособность самого скрипта, например в начале рабочего времени и в конце.
Программу решил писать не я, а стать архитектором, поручив Искусственному интеллекту реализацию идей, и был я довольно раздосадован....с ROS неважно работает ИИ, а сколько раз он указывал что мой скрипт работать не будет и мне нужно обновиться на 7ю версию ROS и без этого вообще никак.....но результат положительный есть, и опыт у ИИ есть, получал я седые волосы с Gemni и Grok, кстати второй очень неплохо пишет короткий код, а вот в многострочный проектах его дерзость в принятии спорных решений просто убивает желание с ним работать, он тот самый неуч:) который может всё, а вот Gemni почти наоборот, и плохо что я не почувствовал явного прогресса от ИИ, иногда приходилось возвращаться по коду, так они не могли воспроизвести уже отработанный рабочий код. Да скрипт в ROS это специфическое, но не Perl и т.п. в конце концов...
начнем:
файл в котором хранятся данные
=================== host_data.txt ========================
192.168.0.2;comp1
192.168.0.3;comp10
====================================================
файл самого скрипта...
===================skript1
:local filePath "flash/host_data.txt" :local fileCheckResult [/file find name=$filePath] :global telegramMessage :global hostStatus :if ([:typeof $hostStatus] = "nothing") do={ :set hostStatus [:toarray ""] :local i :for i from=0 to=129 do={ :set ($hostStatus->$i) -1 } } #:log info "MONITORING_START: Skript zapushen dlya monitoringa uzlov i otpravki Telegram." :if ($fileCheckResult = "") do={ :set telegramMessage "MONITORING_ERROR: FAIL flash/host_ping.txt NE NAIDEN!" :log error $telegramMessage :log info "MONITORING_TELEGRAM_FILE_ALERT: Vyzyvayu telegram_api_get dlya faila." /system script run telegram_api_get :log info "MONITORING_TELEGRAM_FILE_ALERT: telegram_api_get vyzvan dlya faila." :return } :local fileContent [/file get $filePath contents] :local remainingContent $fileContent :local lineCount 0 :local currentLine "" :local newlinePos 0 :while ([:len $remainingContent] > 0) do={ :set newlinePos [:find $remainingContent "\n"] :if ($newlinePos != -1) do={ :set currentLine [:pick $remainingContent 0 $newlinePos] :set remainingContent [:pick $remainingContent ($newlinePos + 1) [:len $remainingContent]] # :log info $newlinePos } else={ :set currentLine $remainingContent :set remainingContent "" } :set lineCount ($lineCount + 1) # Ïðîïóñêàåì ïóñòûå ñòðîêè :if ([:len $currentLine] = 0) do={:continue} # Ïðîâåðêà íà ïðåâûøåíèå ìàêñèìàëüíîãî êîëè÷åñòâà ýëåìåíòîâ :if ($lineCount > 130) do={ :set telegramMessage ("MONITORING_ERROR: Prevyøåí limit v 130 uzlov v faile " . $filePath . "!") :log error $telegramMessage :log info "MONITORING_TELEGRAM_LIMIT_ALERT: Vyzyvayu telegram_api_get dlya oshibki limita." /system script run telegram_api_get :log info "MONITORING_TELEGRAM_LIMIT_ALERT: telegram_api_get vyzvan dlya oshibki limita." :return } :local ipAddress "" :local nodeName "" :local semicolonPos [:find $currentLine ";"] :if ($semicolonPos != -1) do={ :set ipAddress [:pick $currentLine 0 $semicolonPos] :set nodeName [:pick $currentLine ($semicolonPos + 1) [:len $currentLine]] # :log info ("MONITORING_INFO: Obrabotka uzla: " . $nodeName . " (" . $ipAddress . ")") } else={ :set telegramMessage ("MONITORING_WARNING: Nepravilniy format stroki #" . $lineCount . ": '" . $currentLine . "'. Propuskaem.") # :log warning $telegramMessage # :log info "MONITORING_TELEGRAM_FORMAT_ALERT: Vyzyvayu telegram_api_get dlya oshibki formata." /system script run telegram_api_get # :log info "MONITORING_TELEGRAM_FORMAT_ALERT: telegram_api_get vyzvan dlya oshibki formata." :continue } :local pingCommandResult [/ping $ipAddress count=3 interface=bridge] :local currentStatus :if ($pingCommandResult = 0) do={ :set currentStatus 0 } else={ :set currentStatus 1 } :local arrayIndex ($lineCount - 1) :local previousStatus ($hostStatus->$arrayIndex) :if ($currentStatus != $previousStatus) do={ :if ($currentStatus = 0) do={ :set telegramMessage ("MONITORING_ALERT: UZEL NE OTVETCHAET: " . $nodeName . " (" . $ipAddress . ")!") /system script run telegram_api_get } else={ :set telegramMessage ("MONITORING_STATUS: UZEL " . $nodeName . " (" . $ipAddress . ") - VOSSTANOVLEN!") /system script run telegram_api_get } } else={ :if ($currentStatus = 0) do={ # :log info ("MONITORING_STATUS: UZEL " . $nodeName . " (" . $ipAddress . ") - OSTAYETSYA NEDOSTUPNYM.") } else={ # :log info ("MONITORING_STATUS: UZEL " . $nodeName . " (" . $ipAddress . ") - OSTAYETSYA DOSTUPNYM.") } } :set ($hostStatus->$arrayIndex) $currentStatus } #:log info "MONITORING_COMPLETE: Skript zavershen."
========================
:global hostStatus :if ([:typeof $hostStatus] != "array") do={ :log warning "UPDATE_HOST_STATUS: non massiv." :return } :local arrayLength [:len $hostStatus] :local i 0 :while ($i < $arrayLength) do={ :local currentValue ($hostStatus->$i) :if ($currentValue = 0) do={ :do { :set ($hostStatus->$i) -1 } on-error={ :log error "UPDATE_HOST_STATUS: error update" } :log info "UPDATE_HOST_STATUS: update" } else={ :log info "UPDATE_HOST_STATUS: non update" } :set i ($i + 1) }
====================
Дальше думаем о sheduler
воскресенье, 19 сентября 2021 г.
объединение двух тестовых фалов в Lazarus (Delphi) "по-старому"...
Просто возмутило осложнение вариантов объединения двух текстовых файлов в Lazarus (Delphi) во множестве вариантов поэтому поступили так:
var tfOut,tfIn:textfile; file_s1,file_s2:string;
...
AssignFile(tfOut, file_s1); AssignFile(tfIn, file_s2); reset(tfIn); try append(tfOut); while not eof(tfIn) do begin readln(tfIn,body_file); writeln(tfOut,body_file); end; CloseFile(tfIn); CloseFile(tfOut); except on E: EInOutError do writeln('File error. Elaboration: ', E.Message); end;