import QtQuick import QtQuick.Layouts import org.kde.plasma.plasmoid import org.kde.plasma.components as PlasmaComponents import org.kde.plasma.plasma5support as Plasma5Support import org.kde.plasma.core as PlasmaCore PlasmoidItem { id: root readonly property int fontSize: (Plasmoid.configuration.fontSize > 0) ? Plasmoid.configuration.fontSize : 16 readonly property color textColor: Plasmoid.configuration.useCustomColor ? Plasmoid.configuration.customColor : PlasmaComponents.Label.color // Настройка заголовка и иконки через присоединенное свойство Plasmoid.title: i18n("Home Meteo") Plasmoid.icon: "applications-system" property string tempValue: "--.-" property string humValue: "--.-" property string tempEmoji: "⏳" property string humEmoji: "⏳" property string lastUpdate: "..." width: 320 height: 180 Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground | PlasmaCore.Types.ConfigurableBackground fullRepresentation: Rectangle { id: mainCanvas implicitWidth: 320 implicitHeight: 180 color: Qt.rgba(root.textColor.r, root.textColor.g, root.textColor.b, 0.2) radius: 15 border.color: root.textColor border.width: 1 clip: true GridLayout { // Привязываемся к краям родителя с внутренним отступом anchors.fill: parent anchors.margins: 10 columns: 2 rowSpacing: 0 // Убираем лишние промежутки между строками columnSpacing: 10 // Заголовки PlasmaComponents.Label { Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter text: "Температура, °C" font.pointSize: root.fontSize * 0.8 color: root.textColor opacity: 0.7 } PlasmaComponents.Label { Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter text: "Влажность, %" font.pointSize: root.fontSize * 0.8 color: root.textColor opacity: 0.7 } // Эмодзи Text { Layout.topMargin: 5 Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter text: root.tempEmoji font.pointSize: root.fontSize * 2.6 } Text { Layout.topMargin: 5 Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter text: root.humEmoji font.pointSize: root.fontSize * 2.6 } // Значения PlasmaComponents.Label { Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter text: root.tempValue font.pointSize: root.fontSize * 1.6 font.bold: true color: root.textColor } PlasmaComponents.Label { Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter text: root.humValue font.pointSize: root.fontSize * 1.6 font.bold: true color: root.textColor } PlasmaComponents.Label { Layout.columnSpan: 2 Layout.fillWidth: true Layout.topMargin: 5 // Небольшой отступ от цифр horizontalAlignment: Text.AlignHCenter text: "Обновлено: " + root.lastUpdate font.pointSize: root.fontSize * 0.6 opacity: 0.7 color: root.textColor } } gradient: Gradient { GradientStop { position: 0.0 color: "azure" } GradientStop { position: 0.7 color: "honeydew" } GradientStop { position: 2.0 color: "lightgoldenrodyellow" } } } // Источник данных для чтения файла Plasma5Support.DataSource { id: fileProcessor engine: "executable" connectedSources: [] onNewData: (source, data) => { let stdout = data.stdout ? data.stdout.trim() : ""; // ШАГ 1: Проверка размера if (source.includes("stat -c%s")) { let size = parseInt(stdout) || 0; if (size > 1024) { fileProcessor.connectSource("> /tmp/arduino_last_run"); console.log("Критический размер файла! Очистка."); } else { // Переход к шагу 2 fileProcessor.connectSource("stat -c%y /tmp/arduino_last_run | awk '{print $2}' | cut -d. -f1"); } } // ШАГ 2: Получение времени (ищем формат 00:00:00) else if (stdout.match(/^\d{2}:\d{2}:\d{2}$/)) { root.lastUpdate = stdout; // Переход к шагу 3 fileProcessor.connectSource("cat /tmp/arduino_last_run"); } // ШАГ 3: Чтение самих данных else if (source.includes("cat ")) { parseData(stdout); } disconnectSource(source); } } Timer { id: refreshTimer interval: 5000 running: true repeat: true triggeredOnStart: true onTriggered: { // Запуск цепочки: проверяем размер. // Если файла нет, echo 0 предотвратит ошибку DataSource. fileProcessor.connectSource("stat -c%s /tmp/arduino_last_run 2>/dev/null || echo 0"); } } function parseData(out) { if (!out) return; let m = out.match(/[-+]?[0-9]*\.?[0-9]+/g) if (m && m.length >= 2) { let t = parseFloat(m[0]) let h = parseFloat(m[1]) root.tempValue = t.toFixed(1) root.humValue = h.toFixed(1) root.tempEmoji = t > 27 ? "🥵" : (t < 22 ? "🥶" : "😊") root.humEmoji = h < 40 ? "😮‍💨" : (h > 60 ? "😶‍🌫️" : "😊") } } Plasma5Support.DataSource { id: scriptLauncher engine: "executable" connectedSources: [] Component.onCompleted: { // В Plasma 6 используем Qt.resolvedUrl для получения пути к текущей папке // .replace("file://", "") нужно, так как DataSource ожидает путь к системе, а не URL let currentDir = Qt.resolvedUrl(".").toString().replace("file://", "") let scriptPath = currentDir + "arduino_bridge.sh" if (scriptPath) { scriptLauncher.connectSource(`chmod +x ${scriptPath} && ${scriptPath}`) } } } }