├── .github
└── workflows
│ ├── ci.yml
│ └── pre-commit.yml
├── .gitignore
├── .pre-commit-config.yaml
├── 3rdparty
├── LICENSE_1_0.txt
└── catch.hpp
├── CMakeLists.txt
├── CONTRIBUTING.md
├── COPYING
├── README.md
├── assets
├── appinfo.rc
├── icon
│ ├── appicon.ico
│ ├── gen_icns.sh
│ ├── gen_icon.sh
│ ├── icon-1024.png
│ ├── icon-128.png
│ ├── icon-144.png
│ ├── icon-16.png
│ ├── icon-180.png
│ ├── icon-192.png
│ ├── icon-24.png
│ ├── icon-256.png
│ ├── icon-32.png
│ ├── icon-48.png
│ ├── icon-512.png
│ ├── icon-64.png
│ ├── icon-inkscape.svg
│ ├── icon.svg
│ └── valeronoi.icns
├── screenshot.png
└── valeronoi.desktop
├── cmake-format.py
├── src
├── config.h.in
├── gui
│ ├── dialog
│ │ ├── about.cpp
│ │ ├── about.h
│ │ ├── about.ui
│ │ ├── export.cpp
│ │ ├── export.h
│ │ ├── export.ui
│ │ ├── log.cpp
│ │ ├── log.h
│ │ ├── log.ui
│ │ ├── robot_config.cpp
│ │ ├── robot_config.h
│ │ ├── robot_config.ui
│ │ ├── settings.cpp
│ │ ├── settings.h
│ │ ├── settings.ui
│ │ ├── update.cpp
│ │ ├── update.h
│ │ └── update.ui
│ ├── graphics_item
│ │ ├── entity_item.cpp
│ │ ├── entity_item.h
│ │ ├── floor_item.cpp
│ │ ├── floor_item.h
│ │ ├── map_based_item.cpp
│ │ ├── map_based_item.h
│ │ ├── map_item.cpp
│ │ ├── map_item.h
│ │ ├── measurement_item.cpp
│ │ └── measurement_item.h
│ └── widget
│ │ ├── display_widget.cpp
│ │ └── display_widget.h
├── main.cpp
├── res
│ ├── SourceCodePro-Regular.otf
│ ├── colormaps.json
│ └── valeronoi.png
├── robot
│ ├── api
│ │ ├── sse.cpp
│ │ ├── sse.h
│ │ ├── valetudo_v2.cpp
│ │ └── valetudo_v2.h
│ ├── commands.h
│ ├── connection_configuration.cpp
│ ├── connection_configuration.h
│ ├── robot.cpp
│ ├── robot.h
│ ├── robot_information.cpp
│ ├── robot_information.h
│ ├── wifi_information.cpp
│ └── wifi_information.h
├── state
│ ├── measurements.cpp
│ ├── measurements.h
│ ├── robot_map.cpp
│ ├── robot_map.h
│ ├── state.cpp
│ ├── state.h
│ ├── wifi_collection.cpp
│ └── wifi_collection.h
├── util
│ ├── colormap.h
│ ├── compat.h
│ ├── log_helper.cpp
│ ├── log_helper.h
│ ├── segment_generator.cpp
│ └── segment_generator.h
├── valeronoi.cpp
├── valeronoi.h
├── valeronoi.qrc
└── valeronoi.ui
├── tests
├── test_colormap.cpp
└── test_main.cpp
└── tools
├── pkgbuild
└── valeronoi-git
│ └── PKGBUILD
└── windows
├── copy_dlls.py
└── install.nsi
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Continuous Integration
2 |
3 | on:
4 | push:
5 | release:
6 | types:
7 | - "published"
8 |
9 | jobs:
10 | ci-macos:
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | include:
15 | - os: macos-14
16 | qt: "6.8.0"
17 | cgal: "6.0.1"
18 | variant: "current"
19 | - os: macos-13
20 | qt: "6.5.3"
21 | cgal: "5.6.2"
22 | variant: "legacy"
23 | name: CI macOS ${{ matrix.variant }} (${{ matrix.os }}/Qt ${{ matrix.qt }}/CGAL ${{ matrix.cgal }})
24 | runs-on: ${{ matrix.os }}
25 | env:
26 | HOMEBREW_NO_ANALYTICS: 1
27 | steps:
28 | - uses: actions/checkout@v4
29 | - name: Install dependencies
30 | run: |
31 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
32 | brew analytics off
33 | brew install cmake create-dmg mpfr boost openssl@1.1
34 | - name: Install Qt
35 | uses: jurplel/install-qt-action@v4
36 | with:
37 | version: ${{ matrix.qt }}
38 | - name: Install CGAL
39 | env:
40 | CGAL_VERSION: ${{ matrix.cgal }}
41 | run: |
42 | mkdir /tmp/cgal
43 | cd /tmp/cgal
44 | wget https://github.com/CGAL/cgal/releases/download/v$CGAL_VERSION/CGAL-$CGAL_VERSION.tar.xz
45 | tar xf CGAL-$CGAL_VERSION.tar.xz
46 | mkdir CGAL-$CGAL_VERSION/build
47 | cd CGAL-$CGAL_VERSION/build
48 | cmake .. -DCMAKE_BUILD_TYPE=Release
49 | sudo make install
50 | - name: Build on macOS
51 | env:
52 | OS: ${{ matrix.os }}
53 | QT_VERSION: ${{ matrix.qt }}
54 | VARIANT: ${{ matrix.variant }}
55 | run: |
56 | mkdir build
57 | cd build
58 | cmake .. -DCMAKE_BUILD_TYPE=Release -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1
59 | make -j
60 | ./valeronoi-tests
61 | macdeployqt valeronoi.app
62 | mkdir dist
63 | mv valeronoi.app dist/Valeronoi.app
64 | create-dmg --hdiutil-verbose --no-internet-enable --skip-jenkins --volname "Valeronoi Installer" --volicon "../assets/icon/valeronoi.icns" --window-pos 200 120 --window-size 800 400 --icon-size 100 --icon "Valeronoi.app" 200 190 --hide-extension "Valeronoi.app" --app-drop-link 600 185 "Valeronoi-macOS-Intel-$VARIANT.dmg" "dist/"
65 | - name: Upload artifact
66 | uses: actions/upload-artifact@v4
67 | with:
68 | name: valeronoi-macos-${{ matrix.variant }}
69 | path: build/Valeronoi-macOS-Intel-${{ matrix.variant }}.dmg
70 | - name: Upload release binary
71 | if: ${{ github.event_name == 'release' }}
72 | uses: alexellis/upload-assets@0.4.1
73 | env:
74 | GITHUB_TOKEN: ${{ github.token }}
75 | with:
76 | asset_paths: '["build/Valeronoi-macOS-Intel-${{ matrix.variant }}.dmg"]'
77 | ci-windows:
78 | strategy:
79 | fail-fast: false
80 | matrix:
81 | sys: [mingw64] # mingw32, ucrt64 - Experimental
82 | name: CI Windows/MSYS2
83 | runs-on: windows-2022
84 | steps:
85 | - uses: actions/checkout@v4
86 | - name: Install msys2
87 | uses: msys2/setup-msys2@v2
88 | with:
89 | msystem: ${{ matrix.sys }}
90 | install: >-
91 | base-devel
92 | git
93 | make
94 | zip
95 | pacboy: >-
96 | cmake:p
97 | ninja:p
98 | gcc:p
99 | cc:p
100 | qt6-tools:p
101 | qt6-base:p
102 | qt6-imageformats:p
103 | qt6-svg:p
104 | openssl:p
105 | cgal:p
106 | eigen3:p
107 | intel-tbb:p
108 | nsis:p
109 | location: C:\msys2
110 | - name: Build on Windows
111 | shell: msys2 {0}
112 | run: |
113 | mkdir build
114 | cd build
115 | cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release
116 | cmake --build .
117 | ./valeronoi-tests.exe
118 | mkdir dist
119 | mv valeronoi.exe dist/valeronoi.exe
120 | cp ../COPYING dist
121 | cp ../assets/appinfo.rc dist
122 | mkdir dist/icon
123 | cp ../assets/icon/appicon.ico dist/icon
124 | cd dist
125 | python ../../tools/windows/copy_dlls.py
126 | zip -r ../Valeronoi-Windows-portable-x86_64.zip .
127 | - name: Upload portable archive
128 | uses: actions/upload-artifact@v4
129 | with:
130 | name: valeronoi-windows-portable-${{ matrix.sys }}
131 | path: build/dist
132 | - name: Upload release portable archive
133 | if: ${{ github.event_name == 'release' }}
134 | uses: alexellis/upload-assets@0.4.1
135 | env:
136 | GITHUB_TOKEN: ${{ github.token }}
137 | with:
138 | asset_paths: '["build/Valeronoi-Windows-portable-x86_64.zip"]'
139 | - name: Build installer
140 | shell: msys2 {0}
141 | run: |
142 | cd build/dist
143 | cp ../../tools/windows/install.nsi .
144 | makensis install.nsi
145 | - name: Upload installer
146 | uses: actions/upload-artifact@v4
147 | with:
148 | name: valeronoi-windows-installer-${{ matrix.sys }}
149 | path: build/dist/Valeronoi-installer-x86_64.exe
150 | - name: Upload release portable archive
151 | if: ${{ github.event_name == 'release' }}
152 | uses: alexellis/upload-assets@0.4.1
153 | env:
154 | GITHUB_TOKEN: ${{ github.token }}
155 | with:
156 | asset_paths: '["build/dist/Valeronoi-installer-x86_64.exe"]'
157 | ci-linux:
158 | strategy:
159 | fail-fast: false
160 | matrix:
161 | include:
162 | - os: ubuntu-24.04
163 | qt: "6.8.0"
164 | cgal: "6.0.1"
165 | variant: "current"
166 | - os: ubuntu-22.04
167 | qt: "6.5.3"
168 | cgal: "5.6.2"
169 | variant: "legacy"
170 | name: CI Linux/AppImage ${{ matrix.variant }} (${{ matrix.os }}/Qt ${{ matrix.qt }}/CGAL ${{ matrix.cgal }})
171 | runs-on: ${{ matrix.os }}
172 | steps:
173 | - uses: actions/checkout@v4
174 | - name: Install Qt
175 | uses: jurplel/install-qt-action@v4
176 | with:
177 | version: ${{ matrix.qt }}
178 | - name: Install dependencies
179 | run: |
180 | sudo apt-get install libfuse2 openssl libxcb-xkb-dev libxcb-cursor-dev libxkbcommon-x11-0 cmake xz-utils libmpfr-dev libboost-dev -y
181 | - name: Install CGAL
182 | env:
183 | CGAL_VERSION: ${{ matrix.cgal }}
184 | run: |
185 | mkdir -p /tmp/cgal
186 | cd /tmp/cgal
187 | wget https://github.com/CGAL/cgal/releases/download/v$CGAL_VERSION/CGAL-$CGAL_VERSION.tar.xz
188 | tar xf CGAL-$CGAL_VERSION.tar.xz
189 | mkdir CGAL-$CGAL_VERSION/build
190 | cd CGAL-$CGAL_VERSION/build
191 | cmake .. -DCMAKE_BUILD_TYPE=Release
192 | sudo make install
193 | - name: Build on Linux
194 | env:
195 | OS: ${{ matrix.os }}
196 | QT_VERSION: ${{ matrix.qt }}
197 | VARIANT: ${{ matrix.variant }}
198 | run: |
199 | mkdir build
200 | cd build
201 | cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
202 | make -j install DESTDIR=AppDir
203 | ./valeronoi-tests
204 | mkdir tools
205 | cd tools
206 | wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
207 | wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
208 | chmod +x *
209 | cd ..
210 | export PATH=$Qt6_DIR/bin:$PATH
211 | tools/linuxdeploy-x86_64.AppImage --appdir AppDir -i ../assets/icon/icon-256.png -d AppDir/usr/share/applications/valeronoi.desktop --output appimage --plugin qt
212 | mv Valeronoi-*.AppImage "Valeronoi-${VARIANT}-x86_64.AppImage"
213 | shell: bash
214 | - name: Upload artifact
215 | uses: actions/upload-artifact@v4
216 | with:
217 | name: valeronoi-linux-appimage-${{ matrix.variant }}
218 | path: build/Valeronoi-${{ matrix.variant }}-x86_64.AppImage
219 | - name: Upload release AppImage
220 | if: ${{ github.event_name == 'release' }}
221 | uses: alexellis/upload-assets@0.4.1
222 | env:
223 | GITHUB_TOKEN: ${{ github.token }}
224 | with:
225 | asset_paths: '["build/Valeronoi-${{ matrix.variant }}-x86_64.AppImage"]'
226 |
--------------------------------------------------------------------------------
/.github/workflows/pre-commit.yml:
--------------------------------------------------------------------------------
1 | name: pre-commit
2 |
3 | on: [push]
4 |
5 | jobs:
6 | pre-commit:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v4
10 | - uses: actions/setup-python@v5
11 | - uses: actions/setup-go@v5
12 | with:
13 | go-version: "stable"
14 | - name: Install dependencies
15 | run: |
16 | sudo apt-get install cppcheck -y
17 | go install mvdan.cc/sh/v3/cmd/shfmt@latest
18 | - uses: pre-commit/action@v3.0.1
19 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # See https://pre-commit.com for more information
2 | repos:
3 | - repo: https://github.com/timothycrosley/isort
4 | rev: 5.13.2
5 | hooks:
6 | - id: isort
7 | - repo: https://github.com/ambv/black
8 | rev: 24.10.0
9 | hooks:
10 | - id: black
11 | - repo: https://github.com/pre-commit/pre-commit-hooks
12 | rev: v5.0.0
13 | hooks:
14 | - id: check-merge-conflict
15 | - id: check-yaml
16 | - id: check-json
17 | - id: check-xml
18 | - id: destroyed-symlinks
19 | - id: end-of-file-fixer
20 | - id: mixed-line-ending
21 | - id: trailing-whitespace
22 | - id: fix-byte-order-marker
23 | - repo: https://github.com/pre-commit/mirrors-prettier
24 | rev: v4.0.0-alpha.8
25 | hooks:
26 | - id: prettier
27 | - repo: https://github.com/jumanjihouse/pre-commit-hooks
28 | rev: 3.0.0
29 | hooks:
30 | - id: shellcheck
31 | - id: shfmt
32 | - id: script-must-have-extension
33 | - repo: https://gitlab.com/daverona/pre-commit/cpp
34 | rev: 0.8.0
35 | hooks:
36 | - id: clang-format
37 | - repo: https://github.com/cheshirekow/cmake-format-precommit
38 | rev: v0.6.13
39 | hooks:
40 | - id: cmake-format
41 | - id: cmake-lint
42 |
43 | exclude: (3rdparty/.*)
44 |
--------------------------------------------------------------------------------
/3rdparty/LICENSE_1_0.txt:
--------------------------------------------------------------------------------
1 | Boost Software License - Version 1.0 - August 17th, 2003
2 |
3 | Permission is hereby granted, free of charge, to any person or organization
4 | obtaining a copy of the software and accompanying documentation covered by
5 | this license (the "Software") to use, reproduce, display, distribute,
6 | execute, and transmit the Software, and to prepare derivative works of the
7 | Software, and to permit third-parties to whom the Software is furnished to
8 | do so, all subject to the following:
9 |
10 | The copyright notices in the Software and this entire statement, including
11 | the above license grant, this restriction and the following disclaimer,
12 | must be included in all copies of the Software, in whole or in part, and
13 | all derivative works of the Software, unless such copies or derivative
14 | works are solely in the form of machine-executable object code generated by
15 | a source language processor.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | DEALINGS IN THE SOFTWARE.
24 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.12)
2 | project(
3 | Valeronoi
4 | VERSION 0.2.2
5 | LANGUAGES CXX
6 | )
7 |
8 | set(CGAL_DO_NOT_WARN_ABOUT_CMAKE_BUILD_TYPE TRUE)
9 |
10 | execute_process(
11 | COMMAND git log -1 --format=%h
12 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
13 | OUTPUT_VARIABLE GIT_COMMIT
14 | OUTPUT_STRIP_TRAILING_WHITESPACE
15 | )
16 | message(STATUS "Git commit is ${GIT_COMMIT}")
17 |
18 | find_package(Threads REQUIRED)
19 | find_package(OpenSSL REQUIRED)
20 | find_package(CGAL REQUIRED)
21 |
22 | find_package(
23 | Qt6
24 | COMPONENTS Core Widgets Network Svg OpenGLWidgets
25 | REQUIRED
26 | )
27 | include(CheckIPOSupported)
28 |
29 | check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error)
30 | if(ipo_supported)
31 | message(STATUS "Enabling interprocedural optimization")
32 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
33 | else()
34 | message(STATUS "Interprocedural optimization not supported: ${ipo_error}")
35 | endif()
36 |
37 | set(CMAKE_CXX_STANDARD 17)
38 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
39 |
40 | include_directories(. "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/3rdparty")
41 |
42 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
43 | message(STATUS "Setting build type to 'Release' as none was specified.")
44 | set(CMAKE_BUILD_TYPE
45 | "Release"
46 | CACHE STRING "Choose the type of build." FORCE
47 | )
48 | endif()
49 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
50 |
51 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
52 | "Clang"
53 | )
54 | add_compile_options(-Wall -Wextra -pedantic -Werror)
55 |
56 | option(COMPILE_NATIVE
57 | "Compile for 'native' architecture (non-portable, but faster binary)"
58 | OFF
59 | )
60 | if(COMPILE_NATIVE)
61 | message(STATUS "Building binary for native architecture")
62 | add_compile_options(-march=native)
63 | endif()
64 | endif()
65 |
66 | configure_file(src/config.h.in config.h)
67 |
68 | set(CMAKE_AUTOGEN_PARALLEL 1)
69 | set(CMAKE_AUTOMOC ON)
70 | set(CMAKE_AUTORCC ON)
71 | set(CMAKE_AUTOUIC ON)
72 |
73 | set(SOURCE_FILES
74 | src/main.cpp
75 | src/valeronoi.ui
76 | src/valeronoi.qrc
77 | src/valeronoi.cpp
78 | src/util/segment_generator.cpp
79 | src/util/log_helper.cpp
80 | src/robot/robot.cpp
81 | src/robot/connection_configuration.cpp
82 | src/robot/robot_information.cpp
83 | src/robot/wifi_information.cpp
84 | src/robot/api/sse.cpp
85 | src/robot/api/valetudo_v2.cpp
86 | src/state/state.cpp
87 | src/state/robot_map.cpp
88 | src/state/measurements.cpp
89 | src/state/wifi_collection.cpp
90 | src/gui/dialog/robot_config.ui
91 | src/gui/dialog/robot_config.cpp
92 | src/gui/dialog/about.ui
93 | src/gui/dialog/about.cpp
94 | src/gui/dialog/update.ui
95 | src/gui/dialog/update.cpp
96 | src/gui/dialog/settings.ui
97 | src/gui/dialog/settings.cpp
98 | src/gui/dialog/export.ui
99 | src/gui/dialog/export.cpp
100 | src/gui/dialog/log.ui
101 | src/gui/dialog/log.cpp
102 | src/gui/widget/display_widget.cpp
103 | src/gui/graphics_item/map_based_item.cpp
104 | src/gui/graphics_item/map_item.cpp
105 | src/gui/graphics_item/floor_item.cpp
106 | src/gui/graphics_item/entity_item.cpp
107 | src/gui/graphics_item/measurement_item.cpp
108 | )
109 |
110 | set(TEST_FILES tests/test_main.cpp tests/test_colormap.cpp)
111 |
112 | set(MACOSX_BUNDLE_BUNDLE_NAME "Valeronoi")
113 | set(MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION}")
114 | set(MACOSX_BUNDLE_COPYRIGHT
115 | "2021-2024 Christian Friedrich Coors, released under GPLv3"
116 | )
117 | set(MACOSX_BUNDLE_ICON_FILE "valeronoi.icns")
118 | set(MACOSX_BUNDLE_LONG_VERSION_STRING "${CMAKE_PROJECT_VERSION}")
119 | set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_PROJECT_VERSION}")
120 |
121 | add_executable(
122 | valeronoi WIN32 MACOSX_BUNDLE
123 | ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/assets/icon/valeronoi.icns
124 | ${CMAKE_SOURCE_DIR}/assets/appinfo.rc
125 | )
126 | target_compile_options(valeronoi PRIVATE -fPIC)
127 | add_executable(valeronoi-tests ${TEST_FILES})
128 |
129 | target_link_libraries(
130 | valeronoi
131 | PRIVATE Threads::Threads
132 | Qt6::Core
133 | Qt6::Widgets
134 | Qt6::Network
135 | Qt6::Svg
136 | Qt6::OpenGLWidgets
137 | CGAL::CGAL
138 | OpenSSL::SSL
139 | )
140 |
141 | if(APPLE)
142 | install(TARGETS valeronoi BUNDLE DESTINATION Valeronoi)
143 | set_source_files_properties(
144 | ${CMAKE_SOURCE_DIR}/assets/icon/valeronoi.icns
145 | PROPERTIES MACOSX_PACKAGE_LOCATION "Resources"
146 | )
147 | elseif(NOT WIN32)
148 | install(
149 | TARGETS valeronoi
150 | RUNTIME DESTINATION bin
151 | LIBRARY DESTINATION lib
152 | ARCHIVE DESTINATION lib/static
153 | )
154 | install(FILES ${CMAKE_SOURCE_DIR}/assets/valeronoi.desktop
155 | DESTINATION share/applications
156 | )
157 | install(FILES ${CMAKE_SOURCE_DIR}/COPYING
158 | DESTINATION share/licenses/valeronoi/LICENSE
159 | )
160 | foreach(
161 | icon_size
162 | 16
163 | 24
164 | 32
165 | 48
166 | 64
167 | 128
168 | 144
169 | 180
170 | 192
171 | 256
172 | 512
173 | 1024
174 | )
175 | install(
176 | FILES ${CMAKE_SOURCE_DIR}/assets/icon/icon-${icon_size}.png
177 | DESTINATION share/icons/hicolor/${icon_size}x${icon_size}/apps
178 | RENAME valeronoi.png
179 | )
180 | endforeach()
181 | install(
182 | FILES ${CMAKE_SOURCE_DIR}/assets/icon/icon.svg
183 | DESTINATION share/icons/hicolor/scalable/apps
184 | RENAME valeronoi.svg
185 | )
186 | endif()
187 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions to Valeronoi are welcome! Please note that this project is licensed under the GPLv3, so your contributions will also fall under that license.
4 |
5 | ## Development
6 |
7 | Make sure to follow the existing project structure. The Qt-Dialog files (\*.ui) are generated using the Qt 5 Designer, so they should be compatible with both Qt 5 and Qt 6. This project has a [pre-commit](https://pre-commit.com/) config, so make sure any PRs pass the pre-commit checks.
8 |
9 | By default, IPO Optimizations are enabled. This can lead to highly increased linking times. During development it is advised to disable IPO (e.g. remove `set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)` from CMakeLists.txt).
10 |
11 | ### Coding conventions
12 |
13 | - Include guards: `#ifndef VALERONOI_$PATH$_$FILENAME$_H`
14 | - Variables: `snake_case`
15 | - Members: `m_name`
16 | - Qt Signals: `signal_name`
17 | - Qt Slots: `slot_name`
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Valeronoi
2 |
3 | Valeronoi (Valetudo + Voronoi) is a companion for [Valetudo](https://valetudo.cloud) for generating WiFi signal strength maps. It visualizes them using a [Voronoi diagram](https://en.wikipedia.org/wiki/Voronoi_diagram).
4 |
5 | 
6 |
7 | ## Installation
8 |
9 | Binary distributions are available for Linux, macOS and Windows (x86_64). They can be found in the [releases](https://github.com/ccoors/Valeronoi/releases).
10 |
11 | - Linux: [AppImages](https://appimage.org/). The "current" AppImage is built on Ubuntu 24.04 LTS (Noble Numbat) and Qt 6, so it probably won't run on anything older than that. In that case you may want to test the "legacy" AppImage, which is built on Ubuntu 22.04 LTS (Jammy Jellyfish) instead.
12 | - macOS: "current" is built on macOS 14 (Sonoma) on Intel Macs. It also works with Rosetta 2 on ARM-based Macs. "legacy" is built on macOS 13 (Ventura).
13 | - Windows: Compiled on Windows with mingw64. Available as an installer and a portable zip. Using the uninstaller generated by the installer also removes the registry keys used for the settings stored by Valeronoi.
14 |
15 | ## Basic Usage
16 |
17 | 1. Make sure you have a supported robot running a recent Valetudo version (API v2). Having persistent maps is highly recommended.
18 | 2. Set up the robot connection in Valeronoi (Robot -> Setup)
19 | 3. Connect Valeronoi to the robot using the "Connect" button
20 | 4. Verify that the complete, correct map is displayed (!) See below for an explanation.
21 | 5. Start recording WiFi measurements by clicking the "Begin recording" button
22 | 6. Start a cleanup, either using the controls in the "Control" tab or Valetudo/Home Assistant/... If you don't have persistent maps, make sure to not start a full cleanup! Major map updates can not be handled in Valeronoi.
23 | 7. While cleaning, watch the map update
24 | 8. After the robot returned to the dock, stop the recording and/or disconnect Valeronoi
25 |
26 | ### Persistent maps
27 |
28 | If you have a robot that does not support persistent maps (Roborock V1) or don't have that feature enabled, make sure to only record when doing partial cleanups, as a new map will always be generated on a full cleanup. Major map changes during recording can change the internal map coordinates and mess up the recording.
29 |
30 | ## Support
31 |
32 | ### Graphics
33 |
34 | If the graphics are slow and unresponsive, try the following things in the "Display" tab:
35 |
36 | - Disable drawing the floor
37 | - Disabling the "Restrict to ..." checkboxes
38 | - Increase the "Simplify" slider
39 | - Enabling drawing using OpenGL
40 |
41 | **Warning:** Using OpenGL may increase or decrease performance, depending on your system. Enabling OpenGL can also lead to various issues, like garbage text or inverted graphics. Valeronoi requests OpenGL 3.2, which should be available on most systems, but may not be available in VMs or Remote Desktop scenarios.
42 |
43 | ## Building from source
44 |
45 | Install the required Libraries using the method of your choice:
46 |
47 | - Qt 6
48 | - CGAL (4.x/5.x/6.x should work)
49 |
50 | You also need a C++-Compiler capable of C++17. g++ 7 or later works.
51 |
52 | Then use the CMake-Project as you would in any other project.
53 |
54 | ```
55 | mkdir build && cd build
56 | cmake .. -DCMAKE_BUILD_TYPE=Release
57 | make -j
58 | ```
59 |
60 | ### Arch Linux
61 |
62 | A `PKGBUILD` for the `valeronoi-git` package is provided in `tools/pkgbuild/valeronoi-git`. To build and install it run `makepkg -si`.
63 |
64 | ## License
65 |
66 | GPLv3
67 |
--------------------------------------------------------------------------------
/assets/appinfo.rc:
--------------------------------------------------------------------------------
1 | IDI_ICON1 ICON DISCARDABLE "icon/appicon.ico"
2 |
--------------------------------------------------------------------------------
/assets/icon/appicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/appicon.ico
--------------------------------------------------------------------------------
/assets/icon/gen_icns.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | mkdir valeronoi.iconset
4 | sips -z 16 16 icon-1024.png --out valeronoi.iconset/icon_16x16.png
5 | sips -z 32 32 icon-1024.png --out valeronoi.iconset/icon_16x16@2x.png
6 | sips -z 32 32 icon-1024.png --out valeronoi.iconset/icon_32x32.png
7 | sips -z 64 64 icon-1024.png --out valeronoi.iconset/icon_32x32@2x.png
8 | sips -z 128 128 icon-1024.png --out valeronoi.iconset/icon_128x128.png
9 | sips -z 256 256 icon-1024.png --out valeronoi.iconset/icon_128x128@2x.png
10 | sips -z 256 256 icon-1024.png --out valeronoi.iconset/icon_256x256.png
11 | sips -z 512 512 icon-1024.png --out valeronoi.iconset/icon_256x256@2x.png
12 | sips -z 512 512 icon-1024.png --out valeronoi.iconset/icon_512x512.png
13 | cp icon-1024.png valeronoi.iconset/icon_512x512@2x.png
14 | iconutil -c icns valeronoi.iconset
15 | rm -r valeronoi.iconset
16 |
--------------------------------------------------------------------------------
/assets/icon/gen_icon.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euxo pipefail
4 |
5 | cd "$(dirname "${BASH_SOURCE[0]}")"
6 | sizes=(16 24 32 48 64 128 144 180 192 256 512 1024)
7 | input="icon"
8 |
9 | for size in "${sizes[@]}"; do
10 | outfile="${input}-${size}.png"
11 | inkscape --export-filename "$outfile" -w "$size" -h "$size" "${input}.svg"
12 | optipng -o7 "$outfile"
13 | done
14 |
15 | magick convert icon-16.png icon-32.png icon-256.png appicon.ico
16 | cp icon-256.png ../../src/res/valeronoi.png
17 |
--------------------------------------------------------------------------------
/assets/icon/icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-1024.png
--------------------------------------------------------------------------------
/assets/icon/icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-128.png
--------------------------------------------------------------------------------
/assets/icon/icon-144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-144.png
--------------------------------------------------------------------------------
/assets/icon/icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-16.png
--------------------------------------------------------------------------------
/assets/icon/icon-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-180.png
--------------------------------------------------------------------------------
/assets/icon/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-192.png
--------------------------------------------------------------------------------
/assets/icon/icon-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-24.png
--------------------------------------------------------------------------------
/assets/icon/icon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-256.png
--------------------------------------------------------------------------------
/assets/icon/icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-32.png
--------------------------------------------------------------------------------
/assets/icon/icon-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-48.png
--------------------------------------------------------------------------------
/assets/icon/icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-512.png
--------------------------------------------------------------------------------
/assets/icon/icon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/icon-64.png
--------------------------------------------------------------------------------
/assets/icon/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/icon/valeronoi.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/icon/valeronoi.icns
--------------------------------------------------------------------------------
/assets/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/assets/screenshot.png
--------------------------------------------------------------------------------
/assets/valeronoi.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Type=Application
3 | Name=Valeronoi
4 | Comment=Valeronoi is a companion app for Valetudo for generating WiFi heat maps.
5 | Exec=valeronoi
6 | Icon=valeronoi
7 | Categories=Network;Utility;
8 | Terminal=false
9 |
--------------------------------------------------------------------------------
/cmake-format.py:
--------------------------------------------------------------------------------
1 | with section("format"):
2 | # How wide to allow formatted cmake files
3 | line_width = 80
4 |
5 | # How many spaces to tab for indent
6 | tab_size = 4
7 |
8 | # If true, separate flow control names from their parentheses with a space
9 | separate_ctrl_name_with_space = False
10 |
11 | # If true, separate function names from parentheses with a space
12 | separate_fn_name_with_space = False
13 |
14 | # If a statement is wrapped to more than one line, than dangle the closing
15 | # parenthesis on its own line.
16 | dangle_parens = True
17 |
--------------------------------------------------------------------------------
/src/config.h.in:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_CONFIG_H
19 | #define VALERONOI_CONFIG_H
20 |
21 | // Configured by CMake
22 |
23 | #define VALERONOI_GIT_COMMIT "@GIT_COMMIT@"
24 | #define VALERONOI_VERSION_MAJOR "@Valeronoi_VERSION_MAJOR@"
25 | #define VALERONOI_VERSION_MINOR "@Valeronoi_VERSION_MINOR@"
26 | #define VALERONOI_VERSION_PATCH "@Valeronoi_VERSION_PATCH@"
27 |
28 | #define VALERONOI_VERSION VALERONOI_VERSION_MAJOR "." VALERONOI_VERSION_MINOR "." VALERONOI_VERSION_PATCH
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/gui/dialog/about.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "about.h"
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | #include "config.h"
25 | #include "ui_about.h"
26 |
27 | namespace Valeronoi::gui::dialog {
28 |
29 | AboutDialog::AboutDialog(QWidget *parent)
30 | : QDialog(parent), ui(new Ui::AboutDialog) {
31 | ui->setupUi(this);
32 | ui->version->setText(VALERONOI_VERSION);
33 | ui->gitCommit->setText(VALERONOI_GIT_COMMIT);
34 |
35 | connect(ui->aboutQt, &QPushButton::clicked, this,
36 | [=]() { QMessageBox::aboutQt(this); });
37 | }
38 |
39 | AboutDialog::~AboutDialog() { delete ui; }
40 |
41 | } // namespace Valeronoi::gui::dialog
42 |
--------------------------------------------------------------------------------
/src/gui/dialog/about.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_DIALOG_ABOUT_H
19 | #define VALERONOI_GUI_DIALOG_ABOUT_H
20 |
21 | #include
22 |
23 | QT_BEGIN_NAMESPACE
24 | namespace Ui {
25 | class AboutDialog;
26 | }
27 | QT_END_NAMESPACE
28 |
29 | namespace Valeronoi::gui::dialog {
30 |
31 | class AboutDialog : public QDialog {
32 | Q_OBJECT
33 | public:
34 | explicit AboutDialog(QWidget *parent = nullptr);
35 |
36 | ~AboutDialog() override;
37 |
38 | private:
39 | Ui::AboutDialog *ui;
40 | };
41 |
42 | } // namespace Valeronoi::gui::dialog
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/src/gui/dialog/export.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "export.h"
19 |
20 | #include "ui_export.h"
21 |
22 | namespace Valeronoi::gui::dialog {
23 | ExportDialog::ExportDialog(QWidget *parent)
24 | : QDialog(parent), ui(new Ui::ExportDialog) {
25 | ui->setupUi(this);
26 | setWindowFlags(Qt::Sheet);
27 |
28 | connect(ui->width, QOverload::of(&QSpinBox::valueChanged), this,
29 | [=](int width) {
30 | int new_height = static_cast(width / m_ratio);
31 | if (ui->height->value() != new_height) {
32 | const bool block = ui->height->blockSignals(true);
33 | ui->height->setValue(new_height);
34 | ui->height->blockSignals(block);
35 | }
36 | });
37 |
38 | connect(ui->height, QOverload::of(&QSpinBox::valueChanged), this,
39 | [=](int height) {
40 | int new_width = static_cast(height * m_ratio);
41 | if (ui->width->value() != new_width) {
42 | const bool block = ui->width->blockSignals(true);
43 | ui->width->setValue(new_width);
44 | ui->width->blockSignals(block);
45 | }
46 | });
47 | }
48 |
49 | ExportDialog::~ExportDialog() { delete ui; }
50 |
51 | void ExportDialog::set_size(const QSize &size) {
52 | ui->width->setMaximum(10 * size.width());
53 | ui->height->setMaximum(10 * size.height());
54 | const bool block_w = ui->width->blockSignals(true);
55 | const bool block_h = ui->height->blockSignals(true);
56 | ui->width->setValue(size.width());
57 | ui->height->setValue(size.height());
58 | ui->width->blockSignals(block_w);
59 | ui->height->blockSignals(block_h);
60 | m_ratio =
61 | static_cast(size.width()) / static_cast(size.height());
62 | ui->transparent->setChecked(true);
63 | }
64 |
65 | QSize ExportDialog::get_size() const {
66 | return QSize(ui->width->value(), ui->height->value());
67 | }
68 |
69 | bool ExportDialog::get_transparent() const {
70 | return ui->transparent->isChecked();
71 | }
72 |
73 | } // namespace Valeronoi::gui::dialog
74 |
--------------------------------------------------------------------------------
/src/gui/dialog/export.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_DIALOG_EXPORT_H
19 | #define VALERONOI_GUI_DIALOG_EXPORT_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include "../../robot/robot.h"
27 |
28 | QT_BEGIN_NAMESPACE
29 | namespace Ui {
30 | class ExportDialog;
31 | }
32 | QT_END_NAMESPACE
33 |
34 | namespace Valeronoi::gui::dialog {
35 | class ExportDialog : public QDialog {
36 | Q_OBJECT
37 | public:
38 | explicit ExportDialog(QWidget *parent = nullptr);
39 |
40 | ~ExportDialog() override;
41 |
42 | void set_size(const QSize &size);
43 |
44 | [[nodiscard]] QSize get_size() const;
45 |
46 | [[nodiscard]] bool get_transparent() const;
47 |
48 | private:
49 | Ui::ExportDialog *ui;
50 | double m_ratio;
51 | };
52 | } // namespace Valeronoi::gui::dialog
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/src/gui/dialog/export.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ExportDialog
4 |
5 |
6 | Qt::ApplicationModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 360
13 | 240
14 |
15 |
16 |
17 | Export image
18 |
19 |
20 | -
21 |
22 |
23 | Select image resolution
24 |
25 |
26 |
27 | -
28 |
29 |
-
30 |
31 |
32 | Height
33 |
34 |
35 |
36 | -
37 |
38 |
39 | Width
40 |
41 |
42 |
43 | -
44 |
45 |
46 | Pixels
47 |
48 |
49 |
50 | -
51 |
52 |
53 | Pixels
54 |
55 |
56 |
57 | -
58 |
59 |
60 |
61 | 150
62 | 0
63 |
64 |
65 |
66 | 1
67 |
68 |
69 | 99999
70 |
71 |
72 |
73 | -
74 |
75 |
76 |
77 | 150
78 | 0
79 |
80 |
81 |
82 | 1
83 |
84 |
85 | 99999
86 |
87 |
88 |
89 | -
90 |
91 |
92 | Qt::Horizontal
93 |
94 |
95 |
96 | 40
97 | 20
98 |
99 |
100 |
101 |
102 |
103 |
104 | -
105 |
106 |
107 | Transparent background
108 |
109 |
110 | true
111 |
112 |
113 |
114 | -
115 |
116 |
117 | Qt::Vertical
118 |
119 |
120 |
121 | 20
122 | 35
123 |
124 |
125 |
126 |
127 | -
128 |
129 |
130 | Qt::Horizontal
131 |
132 |
133 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | buttonBox
143 | accepted()
144 | ExportDialog
145 | accept()
146 |
147 |
148 | 248
149 | 254
150 |
151 |
152 | 157
153 | 274
154 |
155 |
156 |
157 |
158 | buttonBox
159 | rejected()
160 | ExportDialog
161 | reject()
162 |
163 |
164 | 316
165 | 260
166 |
167 |
168 | 286
169 | 274
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/src/gui/dialog/log.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "log.h"
19 |
20 | #include "ui_log.h"
21 |
22 | namespace Valeronoi::gui::dialog {
23 |
24 | LogDialog::LogDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LogDialog) {
25 | ui->setupUi(this);
26 |
27 | ui->logText->setFontFamily("Source Code Pro");
28 | }
29 |
30 | LogDialog::~LogDialog() { delete ui; }
31 |
32 | void LogDialog::log_message(const QString &msg) { ui->logText->append(msg); }
33 |
34 | } // namespace Valeronoi::gui::dialog
35 |
--------------------------------------------------------------------------------
/src/gui/dialog/log.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_DIALOG_LOG_H
19 | #define VALERONOI_GUI_DIALOG_LOG_H
20 |
21 | #include
22 |
23 | QT_BEGIN_NAMESPACE
24 | namespace Ui {
25 | class LogDialog;
26 | }
27 | QT_END_NAMESPACE
28 |
29 | namespace Valeronoi::gui::dialog {
30 |
31 | class LogDialog : public QDialog {
32 | Q_OBJECT
33 | public:
34 | explicit LogDialog(QWidget *parent = nullptr);
35 |
36 | ~LogDialog() override;
37 |
38 | void log_message(const QString &msg);
39 |
40 | private:
41 | Ui::LogDialog *ui;
42 | };
43 |
44 | } // namespace Valeronoi::gui::dialog
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/src/gui/dialog/log.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | LogDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 491
10 | 317
11 |
12 |
13 |
14 | Log
15 |
16 |
17 | -
18 |
19 |
20 | Valeronoi log:
21 |
22 |
23 |
24 | -
25 |
26 |
27 | true
28 |
29 |
30 |
31 |
32 |
33 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
34 | <html><head><meta name="qrichtext" content="1" /><style type="text/css">
35 | p, li { white-space: pre-wrap; }
36 | </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;">
37 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>
38 |
39 |
40 |
41 | -
42 |
43 |
44 | Qt::Horizontal
45 |
46 |
47 | QDialogButtonBox::Close
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | buttonBox
57 | accepted()
58 | LogDialog
59 | accept()
60 |
61 |
62 | 248
63 | 254
64 |
65 |
66 | 157
67 | 274
68 |
69 |
70 |
71 |
72 | buttonBox
73 | rejected()
74 | LogDialog
75 | reject()
76 |
77 |
78 | 316
79 | 260
80 |
81 |
82 | 286
83 | 274
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/gui/dialog/robot_config.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "robot_config.h"
19 |
20 | #include
21 | #include
22 |
23 | #include "../../robot/connection_configuration.h"
24 | #include "ui_robot_config.h"
25 |
26 | namespace Valeronoi::gui::dialog {
27 | RobotConfigDialog::RobotConfigDialog(QWidget *parent)
28 | : QDialog(parent),
29 | ui(new Ui::RobotConfigDialog),
30 | m_progress_dialog(tr("Testing connection..."), tr("Cancel"), 0, 100,
31 | this) {
32 | ui->setupUi(this);
33 | setWindowFlags(Qt::Sheet);
34 |
35 | m_progress_dialog.setWindowModality(Qt::ApplicationModal);
36 | m_progress_dialog.setAutoClose(true);
37 | m_progress_dialog.close();
38 | connect(&m_progress_dialog, &QProgressDialog::canceled, this,
39 | &RobotConfigDialog::slot_end_test);
40 |
41 | connect(this, &QDialog::accepted, this, &RobotConfigDialog::slot_save);
42 | connect(ui->buttonTestConnection, &QPushButton::clicked, this,
43 | &RobotConfigDialog::slot_test_connection);
44 |
45 | connect(&m_robot, &Valeronoi::robot::Robot::signal_connecting_step, this,
46 | [=](float value) {
47 | qDebug().nospace() << "Received connection step " << value;
48 | if (!m_test_cancelled) {
49 | m_progress_dialog.setValue(10 + static_cast(80 * value));
50 | }
51 | });
52 | connect(&m_robot, &Valeronoi::robot::Robot::signal_connected, this,
53 | &RobotConfigDialog::slot_robot_connected);
54 | connect(&m_robot, &Valeronoi::robot::Robot::signal_connection_error, this,
55 | &RobotConfigDialog::slot_robot_connection_failed);
56 |
57 | load_settings();
58 | }
59 |
60 | RobotConfigDialog::~RobotConfigDialog() { delete ui; }
61 |
62 | void RobotConfigDialog::slot_save() {
63 | QSettings settings;
64 | ensure_http();
65 |
66 | settings.setValue("robot/url", ui->valetudoAddress->text());
67 | settings.setValue("robot/auth/enabled", ui->groupBoxAuth->isChecked());
68 | settings.setValue("robot/auth/username", ui->authUsername->text());
69 | settings.setValue("robot/auth/password", ui->authPassword->text());
70 |
71 | emit signal_config_changed();
72 | }
73 |
74 | void RobotConfigDialog::load_settings() {
75 | QSettings settings;
76 | ui->valetudoAddress->setText(
77 | settings.value("robot/url", "http://").toString());
78 | ui->groupBoxAuth->setChecked(
79 | settings.value("robot/auth/enabled", false).toBool());
80 | ui->authUsername->setText(
81 | settings.value("robot/auth/username", "").toString());
82 | ui->authPassword->setText(
83 | settings.value("robot/auth/password", "").toString());
84 |
85 | ensure_http();
86 | }
87 |
88 | void RobotConfigDialog::slot_end_test() {
89 | m_test_cancelled = true;
90 | m_robot.slot_disconnect();
91 | m_progress_dialog.close();
92 | }
93 |
94 | void RobotConfigDialog::slot_test_connection() {
95 | ensure_http();
96 | const QString url_input = ui->valetudoAddress->text().trimmed();
97 | if (url_input.isEmpty()) {
98 | QMessageBox::warning(this, tr("Error"),
99 | tr("Please enter the Valetudo address"));
100 | return;
101 | }
102 |
103 | QUrl base_url = QUrl::fromUserInput(url_input);
104 | if (!base_url.isValid()) {
105 | QMessageBox::warning(
106 | this, tr("Error"),
107 | tr("Invalid URL: %1: %2").arg(url_input, base_url.errorString()));
108 | return;
109 | }
110 |
111 | m_test_cancelled = false;
112 | m_progress_dialog.setValue(10);
113 | Valeronoi::robot::ConnectionConfiguration c;
114 | c.m_url = base_url;
115 | c.m_auth = ui->groupBoxAuth->isChecked();
116 | c.m_username = ui->authUsername->text();
117 | c.m_password = ui->authPassword->text();
118 | m_robot.set_connection_configuration(c);
119 | m_robot.slot_connect();
120 | }
121 |
122 | void RobotConfigDialog::slot_robot_connected() {
123 | m_progress_dialog.close();
124 | const auto robot_information = m_robot.get_information();
125 | QString robot_description = QString("%1 / %2 (%3)")
126 | .arg(robot_information->m_manufacturer)
127 | .arg(robot_information->m_model_name)
128 | .arg(robot_information->m_implementation);
129 |
130 | bool has_wifi_config =
131 | robot_information->m_capabilities.contains("WifiConfigurationCapability");
132 |
133 | QString has_wifi_config_description;
134 | if (has_wifi_config) {
135 | has_wifi_config_description =
136 | tr("✅ The robot has the WifiConfigurationCapability.");
137 | } else {
138 | has_wifi_config_description =
139 | tr("❌ The robot does not have the WifiConfigurationCapability.");
140 | }
141 |
142 | m_robot.slot_disconnect();
143 |
144 | QString test_result =
145 | tr("Connection successful. Detected:\n%1\nRunning Valetudo %2\n\n%3")
146 | .arg(robot_description)
147 | .arg(robot_information->m_valetudo_version)
148 | .arg(has_wifi_config_description);
149 |
150 | if (has_wifi_config) {
151 | QMessageBox::information(this, tr("Test successful"), test_result);
152 | } else {
153 | QMessageBox::warning(this, tr("Test failed"), test_result);
154 | }
155 | }
156 |
157 | void RobotConfigDialog::slot_robot_connection_failed() {
158 | m_progress_dialog.close();
159 | QMessageBox::warning(this, tr("Error"),
160 | tr("Test failed:\n%1").arg(m_robot.get_error()));
161 | }
162 |
163 | void RobotConfigDialog::ensure_http() {
164 | const auto current_text = ui->valetudoAddress->text().trimmed();
165 | if (!current_text.startsWith("http://")) {
166 | ui->valetudoAddress->setText(QString("http://").append(current_text));
167 | }
168 | }
169 | } // namespace Valeronoi::gui::dialog
170 |
--------------------------------------------------------------------------------
/src/gui/dialog/robot_config.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_DIALOG_ROBOT_CONFIG_H
19 | #define VALERONOI_GUI_DIALOG_ROBOT_CONFIG_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #include "../../robot/robot.h"
32 |
33 | QT_BEGIN_NAMESPACE
34 | namespace Ui {
35 | class RobotConfigDialog;
36 | }
37 | QT_END_NAMESPACE
38 |
39 | namespace Valeronoi::gui::dialog {
40 | class RobotConfigDialog : public QDialog {
41 | Q_OBJECT
42 | public:
43 | explicit RobotConfigDialog(QWidget *parent = nullptr);
44 |
45 | ~RobotConfigDialog() override;
46 |
47 | void load_settings();
48 |
49 | signals:
50 | void signal_config_changed();
51 |
52 | private slots:
53 | void slot_save();
54 |
55 | void slot_test_connection();
56 |
57 | void slot_end_test();
58 |
59 | void slot_robot_connected();
60 |
61 | void slot_robot_connection_failed();
62 |
63 | private:
64 | void ensure_http();
65 |
66 | Ui::RobotConfigDialog *ui;
67 | QProgressDialog m_progress_dialog;
68 | bool m_test_cancelled{false};
69 |
70 | Valeronoi::robot::Robot m_robot;
71 | };
72 | } // namespace Valeronoi::gui::dialog
73 |
74 | #endif
75 |
--------------------------------------------------------------------------------
/src/gui/dialog/robot_config.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | RobotConfigDialog
4 |
5 |
6 | Qt::ApplicationModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 420
13 | 300
14 |
15 |
16 |
17 |
18 | 0
19 | 0
20 |
21 |
22 |
23 |
24 | 420
25 | 300
26 |
27 |
28 |
29 | Robot Setup
30 |
31 |
32 | -
33 |
34 |
-
35 |
36 |
37 | Valetudo address
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 | 0
46 | 0
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 | HTTP Authentication
60 |
61 |
62 | true
63 |
64 |
65 | false
66 |
67 |
68 |
-
69 |
70 |
-
71 |
72 |
73 | Username
74 |
75 |
76 |
77 | -
78 |
79 |
80 |
81 | 0
82 | 0
83 |
84 |
85 |
86 | valetudo
87 |
88 |
89 |
90 | -
91 |
92 |
93 | Password
94 |
95 |
96 |
97 | -
98 |
99 |
100 |
101 | 0
102 | 0
103 |
104 |
105 |
106 | QLineEdit::Password
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | -
116 |
117 |
118 |
-
119 |
120 |
121 | Qt::Horizontal
122 |
123 |
124 |
125 | 271
126 | 20
127 |
128 |
129 |
130 |
131 | -
132 |
133 |
134 |
135 | 0
136 | 0
137 |
138 |
139 |
140 | Test connection
141 |
142 |
143 |
144 |
145 |
146 |
147 | -
148 |
149 |
150 | Qt::Vertical
151 |
152 |
153 |
154 | 20
155 | 40
156 |
157 |
158 |
159 |
160 | -
161 |
162 |
163 | Qt::Horizontal
164 |
165 |
166 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
167 |
168 |
169 |
170 |
171 |
172 |
173 | valetudoAddress
174 | groupBoxAuth
175 | authUsername
176 | authPassword
177 | buttonTestConnection
178 |
179 |
180 |
181 |
182 | buttonBox
183 | accepted()
184 | RobotConfigDialog
185 | accept()
186 |
187 |
188 | 248
189 | 254
190 |
191 |
192 | 157
193 | 274
194 |
195 |
196 |
197 |
198 | buttonBox
199 | rejected()
200 | RobotConfigDialog
201 | reject()
202 |
203 |
204 | 316
205 | 260
206 |
207 |
208 | 286
209 | 274
210 |
211 |
212 |
213 |
214 |
215 |
--------------------------------------------------------------------------------
/src/gui/dialog/settings.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "settings.h"
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | #include "../../util/compat.h"
25 | #include "ui_settings.h"
26 |
27 | namespace Valeronoi::gui::dialog {
28 | SettingsDialog::SettingsDialog(QWidget *parent)
29 | : QDialog(parent), ui(new Ui::SettingsDialog) {
30 | ui->setupUi(this);
31 | setWindowFlags(Qt::Sheet);
32 |
33 | connect(ui->checkUpdates, &CHECKBOX_SIGNAL_CHANGED, this, [=]() {
34 | QSettings settings;
35 | settings.setValue("app/autoUpdateCheck", ui->checkUpdates->isChecked());
36 | });
37 |
38 | QSettings settings;
39 | ui->checkUpdates->setChecked(
40 | settings.value("app/autoUpdateCheck", false).toBool());
41 | }
42 |
43 | SettingsDialog::~SettingsDialog() { delete ui; }
44 |
45 | bool SettingsDialog::should_auto_check_for_updates(QWidget *parent) {
46 | QSettings settings;
47 | bool check_for_updates{false};
48 | auto update_check = settings.value("app/autoUpdateCheck");
49 | if (update_check.isNull()) {
50 | auto start_count = settings.value("app/startCount", 0).toInt();
51 | if (start_count >= 3) {
52 | const auto clicked_button = QMessageBox::question(
53 | parent, tr("Auto Updates"),
54 | tr("Do you want Valeronoi to automatically check for updates?"));
55 | check_for_updates = (clicked_button == QMessageBox::StandardButton::Yes);
56 | settings.setValue("app/autoUpdateCheck", check_for_updates);
57 | ui->checkUpdates->setChecked(check_for_updates);
58 | }
59 | } else {
60 | check_for_updates = update_check.toBool();
61 | }
62 | return check_for_updates;
63 | }
64 |
65 | } // namespace Valeronoi::gui::dialog
66 |
--------------------------------------------------------------------------------
/src/gui/dialog/settings.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_DIALOG_SETTINGS_H
19 | #define VALERONOI_GUI_DIALOG_SETTINGS_H
20 |
21 | #include
22 |
23 | QT_BEGIN_NAMESPACE
24 | namespace Ui {
25 | class SettingsDialog;
26 | }
27 | QT_END_NAMESPACE
28 |
29 | namespace Valeronoi::gui::dialog {
30 | class SettingsDialog : public QDialog {
31 | Q_OBJECT
32 | public:
33 | explicit SettingsDialog(QWidget *parent = nullptr);
34 |
35 | ~SettingsDialog() override;
36 |
37 | [[nodiscard]] bool should_auto_check_for_updates(QWidget *parent = nullptr);
38 |
39 | private:
40 | Ui::SettingsDialog *ui;
41 | };
42 | } // namespace Valeronoi::gui::dialog
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/src/gui/dialog/settings.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | SettingsDialog
4 |
5 |
6 | Qt::NonModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 400
13 | 150
14 |
15 |
16 |
17 | Settings
18 |
19 |
20 | -
21 |
22 |
23 | Automatically check for updates
24 |
25 |
26 |
27 | -
28 |
29 |
30 | Qt::Vertical
31 |
32 |
33 |
34 | 20
35 | 67
36 |
37 |
38 |
39 |
40 | -
41 |
42 |
43 | Qt::Horizontal
44 |
45 |
46 | QDialogButtonBox::Close
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | buttonBox
56 | accepted()
57 | SettingsDialog
58 | accept()
59 |
60 |
61 | 248
62 | 254
63 |
64 |
65 | 157
66 | 274
67 |
68 |
69 |
70 |
71 | buttonBox
72 | rejected()
73 | SettingsDialog
74 | reject()
75 |
76 |
77 | 316
78 | 260
79 |
80 |
81 | 286
82 | 274
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/src/gui/dialog/update.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "update.h"
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | #include "config.h"
30 | #include "ui_update.h"
31 |
32 | namespace Valeronoi::gui::dialog {
33 |
34 | UpdateDialog::UpdateDialog(QWidget *parent)
35 | : QDialog(parent), ui(new Ui::UpdateDialog) {
36 | ui->setupUi(this);
37 | ui->currentVersion->setText(VALERONOI_VERSION);
38 |
39 | connect(ui->goToRelease, &QPushButton::clicked, this,
40 | [=]() { QDesktopServices::openUrl(m_goto_url); });
41 | }
42 |
43 | UpdateDialog::~UpdateDialog() { delete ui; }
44 |
45 | void UpdateDialog::check_update(bool silent, QWidget *error_parent) {
46 | qDebug() << "Checking for updates";
47 |
48 | auto r = QNetworkRequest(
49 | QUrl("https://api.github.com/repos/ccoors/Valeronoi/releases"));
50 | r.setTransferTimeout(10000);
51 | r.setMaximumRedirectsAllowed(10);
52 | r.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
53 | QNetworkRequest::AlwaysNetwork);
54 | r.setHeader(QNetworkRequest::UserAgentHeader, "Valeronoi/" VALERONOI_VERSION);
55 | auto reply = m_qnam.get(r);
56 | connect(reply, &QNetworkReply::finished, this, [=]() {
57 | if (reply->error() != QNetworkReply::NoError) {
58 | QMessageBox::warning(
59 | error_parent, "Valeronoi",
60 | tr("Update check failed: %1").arg(reply->errorString()));
61 | } else {
62 | auto data = reply->readAll();
63 | QJsonParseError error;
64 | auto json = QJsonDocument::fromJson(data, &error);
65 | if (json.isNull()) {
66 | QMessageBox::warning(
67 | error_parent, "Valeronoi",
68 | tr("Error parsing update data: %1").arg(error.errorString()));
69 | } else {
70 | auto newest_release = json.array()[0].toObject();
71 | auto current_tag = newest_release["tag_name"].toString();
72 | m_goto_url = newest_release["html_url"].toString();
73 | if (current_tag.isEmpty() || m_goto_url.isEmpty()) {
74 | QMessageBox::information(error_parent, "Valeronoi",
75 | tr("Could not load update information"));
76 | return;
77 | }
78 | ui->updatedVersion->setText(current_tag);
79 | if (current_tag != "v" VALERONOI_VERSION) {
80 | open();
81 | raise();
82 | } else if (!silent) {
83 | QMessageBox::information(error_parent, "Valeronoi",
84 | tr("No new version available"));
85 | }
86 | }
87 | }
88 | reply->deleteLater();
89 | });
90 | }
91 |
92 | } // namespace Valeronoi::gui::dialog
93 |
--------------------------------------------------------------------------------
/src/gui/dialog/update.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_DIALOG_UPDATE_H
19 | #define VALERONOI_GUI_DIALOG_UPDATE_H
20 |
21 | #include
22 | #include
23 |
24 | QT_BEGIN_NAMESPACE
25 | namespace Ui {
26 | class UpdateDialog;
27 | }
28 | QT_END_NAMESPACE
29 |
30 | namespace Valeronoi::gui::dialog {
31 |
32 | class UpdateDialog : public QDialog {
33 | Q_OBJECT
34 | public:
35 | explicit UpdateDialog(QWidget *parent = nullptr);
36 |
37 | ~UpdateDialog() override;
38 |
39 | void check_update(bool silent = false, QWidget *error_parent = nullptr);
40 |
41 | private:
42 | Ui::UpdateDialog *ui;
43 |
44 | QUrl m_goto_url;
45 |
46 | QNetworkAccessManager m_qnam;
47 | };
48 |
49 | } // namespace Valeronoi::gui::dialog
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/src/gui/dialog/update.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | UpdateDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 450
10 | 225
11 |
12 |
13 |
14 | Update
15 |
16 |
17 | -
18 |
19 |
20 | A new version of Valeronoi is available:
21 |
22 |
23 |
24 | -
25 |
26 |
-
27 |
28 |
29 | You are running version
30 |
31 |
32 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
33 |
34 |
35 |
36 | -
37 |
38 |
39 | CURRENT_VERSION
40 |
41 |
42 |
43 | -
44 |
45 |
46 | New version
47 |
48 |
49 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
50 |
51 |
52 |
53 | -
54 |
55 |
56 | UPDATED_VERSION
57 |
58 |
59 |
60 |
61 |
62 | -
63 |
64 |
65 |
-
66 |
67 |
68 | Qt::Horizontal
69 |
70 |
71 |
72 | 40
73 | 20
74 |
75 |
76 |
77 |
78 | -
79 |
80 |
81 | Go to release page
82 |
83 |
84 |
85 |
86 |
87 |
88 | -
89 |
90 |
91 | Qt::Vertical
92 |
93 |
94 |
95 | 20
96 | 44
97 |
98 |
99 |
100 |
101 | -
102 |
103 |
104 | Qt::Horizontal
105 |
106 |
107 | QDialogButtonBox::Close
108 |
109 |
110 | false
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | buttonBox
120 | accepted()
121 | UpdateDialog
122 | accept()
123 |
124 |
125 | 248
126 | 254
127 |
128 |
129 | 157
130 | 274
131 |
132 |
133 |
134 |
135 | buttonBox
136 | rejected()
137 | UpdateDialog
138 | reject()
139 |
140 |
141 | 316
142 | 260
143 |
144 |
145 | 286
146 | 274
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/entity_item.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "entity_item.h"
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | namespace Valeronoi::gui::graphics_item {
25 | EntityItem::EntityItem(const Valeronoi::state::RobotMap &robot_map,
26 | QGraphicsItem *parent)
27 | : MapBasedItem(robot_map, parent) {}
28 |
29 | void EntityItem::paint(QPainter *painter,
30 | const QStyleOptionGraphicsItem *option,
31 | QWidget *widget) {
32 | (void)widget;
33 | (void)option;
34 | if (m_robot_map.is_valid()) {
35 | const auto &map = m_robot_map.get_map();
36 | // Draw path(s) first
37 | std::for_each(
38 | map.entities.begin(), map.entities.end(), [=](const auto &entity) {
39 | if ((entity.type == "path" || entity.cls == "PathMapEntity") &&
40 | entity.points.size() > 1) {
41 | QPen pen;
42 | QColor path_color = Qt::white;
43 | path_color.setAlphaF(0.5);
44 | pen.setColor(path_color);
45 | pen.setWidth(2);
46 | painter->setPen(pen);
47 | painter->setBrush(Qt::transparent);
48 | QPainterPath path;
49 | path.moveTo(entity.points[0].x, entity.points[0].y);
50 | for (const auto &p : entity.points) {
51 | path.lineTo(p.x, p.y);
52 | }
53 | painter->drawPath(path);
54 | }
55 | });
56 |
57 | std::for_each(map.entities.begin(), map.entities.end(),
58 | [=](const auto &entity) {
59 | if (entity.points.empty()) {
60 | return;
61 | }
62 | if (entity.type == "charger_location") {
63 | paint_charger(painter, entity);
64 | } else if (entity.type == "robot_position") {
65 | paint_robot(painter, entity);
66 | }
67 | });
68 | }
69 | }
70 |
71 | void EntityItem::paint_robot(QPainter *painter,
72 | const Valeronoi::state::Entity &entity) {
73 | QPen pen;
74 | pen.setColor(Qt::darkGray);
75 | pen.setWidthF(1.5);
76 | painter->setPen(pen);
77 | painter->setBrush(Qt::white);
78 | QPointF robot_center(entity.points[0].x, entity.points[0].y);
79 | painter->drawEllipse(robot_center, 10, 10);
80 | QPointF tower_head(entity.points[0].x, entity.points[0].y);
81 | tower_head += 3 * QPointF(std::cos(entity.angle), std::sin(entity.angle));
82 | pen.setWidthF(1);
83 | painter->setPen(pen);
84 | painter->drawEllipse(tower_head, 3, 3);
85 | }
86 |
87 | void EntityItem::paint_charger(QPainter *painter,
88 | const Valeronoi::state::Entity &entity) {
89 | QPen pen;
90 | pen.setColor(QColor(50, 50, 50));
91 | pen.setWidthF(1.5);
92 | painter->setPen(pen);
93 | painter->setBrush(Qt::lightGray);
94 | QPointF charger_center(entity.points[0].x, entity.points[0].y);
95 | painter->drawEllipse(charger_center, 12, 12);
96 |
97 | QPainterPath path;
98 | path.moveTo(charger_center.x() + 2, charger_center.y() - 6);
99 | path.lineTo(charger_center.x() - 3.5, charger_center.y() + 1);
100 | path.lineTo(charger_center.x() - 1, charger_center.y() + 1);
101 | path.lineTo(charger_center.x() - 2, charger_center.y() + 6);
102 |
103 | path.lineTo(charger_center.x() + 3.5, charger_center.y() - 1);
104 | path.lineTo(charger_center.x() + 1, charger_center.y() - 1);
105 | path.closeSubpath();
106 |
107 | painter->setPen(
108 | QPen(QColor(0, 120, 255), 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
109 | painter->setBrush(Qt::white);
110 | painter->drawPath(path);
111 | }
112 |
113 | } // namespace Valeronoi::gui::graphics_item
114 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/entity_item.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_GRAPHICS_ITEM_ENTITY_ITEM_H
19 | #define VALERONOI_GUI_GRAPHICS_ITEM_ENTITY_ITEM_H
20 |
21 | #include "../../state/robot_map.h"
22 | #include "map_based_item.h"
23 |
24 | namespace Valeronoi::gui::graphics_item {
25 | class EntityItem : public MapBasedItem {
26 | public:
27 | explicit EntityItem(const Valeronoi::state::RobotMap &robot_map,
28 | QGraphicsItem *parent = nullptr);
29 |
30 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
31 | QWidget *widget) override;
32 |
33 | private:
34 | static void paint_charger(QPainter *painter,
35 | const Valeronoi::state::Entity &entity);
36 |
37 | static void paint_robot(QPainter *painter,
38 | const Valeronoi::state::Entity &entity);
39 | };
40 |
41 | } // namespace Valeronoi::gui::graphics_item
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/floor_item.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "floor_item.h"
19 |
20 | namespace Valeronoi::gui::graphics_item {
21 | FloorItem::FloorItem(const Valeronoi::state::RobotMap &robot_map,
22 | QGraphicsItem *parent)
23 | : MapBasedItem(robot_map, parent) {}
24 |
25 | void FloorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
26 | QWidget *widget) {
27 | (void)option;
28 | (void)widget;
29 | painter->setPen(Qt::transparent);
30 |
31 | // Anti aliasing the floor leads to a thin grid
32 | painter->setRenderHints(QPainter::Antialiasing, false);
33 |
34 | painter->setBrush(m_floor_color);
35 | painter->drawPath(m_floor_path);
36 | }
37 |
38 | void FloorItem::set_floor_color(QColor color) {
39 | m_floor_color = color;
40 | update();
41 | }
42 |
43 | void FloorItem::map_updated() {
44 | m_floor_path.clear();
45 | m_floor_path.setFillRule(Qt::WindingFill);
46 | if (m_robot_map.is_valid()) {
47 | const auto &map = m_robot_map.get_map();
48 | const auto floor = map.layers.find("floor");
49 | if (floor != map.layers.end()) {
50 | for (const auto &block : floor->second.blocks) {
51 | m_floor_path.addRect(block.x, block.y, map.pixel_size, map.pixel_size);
52 | }
53 | }
54 | }
55 | MapBasedItem::map_updated();
56 | }
57 |
58 | const QPainterPath &FloorItem::get_floor_path() const { return m_floor_path; }
59 |
60 | } // namespace Valeronoi::gui::graphics_item
61 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/floor_item.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_GRAPHICS_ITEM_FLOOR_ITEM_H
19 | #define VALERONOI_GUI_GRAPHICS_ITEM_FLOOR_ITEM_H
20 |
21 | #include
22 |
23 | #include "../../state/robot_map.h"
24 | #include "map_based_item.h"
25 |
26 | namespace Valeronoi::gui::graphics_item {
27 | class FloorItem : public MapBasedItem {
28 | public:
29 | explicit FloorItem(const Valeronoi::state::RobotMap &robot_map,
30 | QGraphicsItem *parent = nullptr);
31 |
32 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
33 | QWidget *widget) override;
34 |
35 | void set_floor_color(QColor color);
36 |
37 | void map_updated() override;
38 |
39 | [[nodiscard]] const QPainterPath &get_floor_path() const;
40 |
41 | private:
42 | QColor m_floor_color;
43 |
44 | QPainterPath m_floor_path;
45 | };
46 |
47 | } // namespace Valeronoi::gui::graphics_item
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/map_based_item.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "map_based_item.h"
19 |
20 | namespace Valeronoi::gui::graphics_item {
21 | MapBasedItem::MapBasedItem(const Valeronoi::state::RobotMap &robot_map,
22 | QGraphicsItem *parent)
23 | : QGraphicsItem(parent), m_robot_map(robot_map) {}
24 |
25 | QRectF MapBasedItem::boundingRect() const { return m_map_bounds; }
26 |
27 | void MapBasedItem::map_updated() {
28 | QRectF new_bounds;
29 | if (m_robot_map.is_valid()) {
30 | new_bounds = QRectF(0, 0, m_robot_map.get_map().size_x,
31 | m_robot_map.get_map().size_y);
32 | } else {
33 | new_bounds = QRectF(0, 0, 400.0, 50.0);
34 | }
35 | if (new_bounds != m_map_bounds) {
36 | m_map_bounds = new_bounds;
37 | prepareGeometryChange();
38 | }
39 | update();
40 | }
41 |
42 | } // namespace Valeronoi::gui::graphics_item
43 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/map_based_item.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_GRAPHICS_ITEM_MAP_BASED_ITEM_H
19 | #define VALERONOI_GUI_GRAPHICS_ITEM_MAP_BASED_ITEM_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #include "../../state/robot_map.h"
31 |
32 | namespace Valeronoi::gui::graphics_item {
33 |
34 | class MapBasedItem : public QGraphicsItem {
35 | public:
36 | explicit MapBasedItem(const Valeronoi::state::RobotMap &robot_map,
37 | QGraphicsItem *parent = nullptr);
38 |
39 | [[nodiscard]] QRectF boundingRect() const override;
40 |
41 | virtual void map_updated();
42 |
43 | protected:
44 | const Valeronoi::state::RobotMap &m_robot_map;
45 |
46 | QRectF m_map_bounds;
47 | };
48 |
49 | } // namespace Valeronoi::gui::graphics_item
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/map_item.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "map_item.h"
19 |
20 | #include
21 |
22 | namespace Valeronoi::gui::graphics_item {
23 | MapItem::MapItem(const Valeronoi::state::RobotMap &robot_map,
24 | std::function relocate, QGraphicsItem *parent)
25 | : MapBasedItem(robot_map, parent),
26 | m_font("Source Code Pro", 12),
27 | m_relocate(std::move(relocate)) {}
28 |
29 | void MapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
30 | QWidget *widget) {
31 | (void)option;
32 | (void)widget;
33 | painter->setPen(Qt::transparent);
34 | painter->setFont(m_font);
35 |
36 | if (m_robot_map.is_valid()) {
37 | const auto &map = m_robot_map.get_map();
38 |
39 | painter->setBrush(m_wall_color);
40 | painter->setRenderHints(
41 | QPainter::Antialiasing,
42 | false); // Antialiasing the walls leads to a thin grid
43 | const auto walls = map.layers.find("wall");
44 | if (walls != map.layers.end()) {
45 | for (const auto &block : walls->second.blocks) {
46 | painter->drawRect(block.x, block.y, map.pixel_size, map.pixel_size);
47 | }
48 | }
49 | } else {
50 | painter->setBrush(Qt::black);
51 | painter->drawRect(0, 0, 400, 50);
52 | painter->setPen(Qt::lightGray);
53 | painter->drawText(0, 0, 400, 50,
54 | Qt::AlignCenter | Qt::AlignVCenter | Qt::TextWordWrap,
55 | m_robot_map.error_msg());
56 | }
57 | }
58 |
59 | void MapItem::set_wall_color(QColor color) {
60 | m_wall_color = color;
61 | update();
62 | }
63 |
64 | #ifndef QT_NO_CONTEXTMENU
65 | void MapItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
66 | const auto &map = m_robot_map.get_map();
67 | QMenu menu;
68 | QAction *go_to_action = menu.addAction(QObject::tr("Relocate here"));
69 | if (!m_robot_map.is_valid()) {
70 | go_to_action->setEnabled(false);
71 | }
72 | QAction *selected_action = menu.exec(event->screenPos());
73 | if (selected_action == go_to_action) {
74 | m_relocate(event->pos().x() + map.crop_x, event->pos().y() + map.crop_y);
75 | }
76 | }
77 | #endif
78 |
79 | } // namespace Valeronoi::gui::graphics_item
80 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/map_item.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_GRAPHICS_ITEM_MAP_ITEM_H
19 | #define VALERONOI_GUI_GRAPHICS_ITEM_MAP_ITEM_H
20 |
21 | #ifndef QT_NO_CONTEXTMENU
22 | #include
23 | #include
24 | #include
25 | #endif
26 |
27 | #include
28 |
29 | #include "../../state/robot_map.h"
30 | #include "map_based_item.h"
31 |
32 | namespace Valeronoi::gui::graphics_item {
33 | class MapItem : public MapBasedItem {
34 | public:
35 | explicit MapItem(const Valeronoi::state::RobotMap &robot_map,
36 | std::function relocate,
37 | QGraphicsItem *parent = nullptr);
38 |
39 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
40 | QWidget *widget) override;
41 |
42 | void set_wall_color(QColor color);
43 |
44 | #ifndef QT_NO_CONTEXTMENU
45 | void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
46 | #endif
47 |
48 | private:
49 | QFont m_font;
50 | QColor m_wall_color;
51 | std::function
52 | m_relocate; // This is a bit hacky, but since MapItem is not a QObject,
53 | // we can't use signals/slots
54 | };
55 |
56 | } // namespace Valeronoi::gui::graphics_item
57 |
58 | #endif
59 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/measurement_item.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "measurement_item.h"
19 |
20 | #include
21 | #include
22 |
23 | constexpr const int SCALE_FONT_SIZE{15};
24 | constexpr const int SCALE_HISTOGRAM_HEIGHT{70};
25 | constexpr const int SCALE_BAR_HEIGHT{30};
26 | constexpr const int SCALE_WIDTH{200};
27 | constexpr const int SCALE_MARGIN{5};
28 | constexpr const int PATH_DISTANCE{35};
29 | constexpr const QSize SCALE_SIZE{
30 | SCALE_WIDTH, SCALE_BAR_HEIGHT + SCALE_MARGIN + SCALE_HISTOGRAM_HEIGHT};
31 |
32 | namespace Valeronoi::gui::graphics_item {
33 | MeasurementItem::MeasurementItem(const Valeronoi::state::RobotMap &robot_map,
34 | QGraphicsItem *parent)
35 | : MapBasedItem(robot_map, parent), m_font("Source Code Pro") {
36 | m_font.setPixelSize(SCALE_FONT_SIZE);
37 | }
38 |
39 | void MeasurementItem::paint(QPainter *painter,
40 | const QStyleOptionGraphicsItem *option,
41 | QWidget *widget) {
42 | (void)option;
43 | (void)widget;
44 | (void)painter;
45 | painter->setPen(Qt::transparent);
46 | if (m_display_mode == Valeronoi::state::DISPLAY_MODE::None ||
47 | m_color_map == nullptr || m_min >= m_max) {
48 | return;
49 | }
50 | if (m_robot_map.is_valid()) {
51 | if (m_display_mode == Valeronoi::state::DISPLAY_MODE::Voronoi) {
52 | // Rendering Voronoi segments with antialiasing leads to artifacts
53 | painter->setRenderHints(QPainter::Antialiasing, false);
54 | painter->setClipRect(MapBasedItem::boundingRect(), Qt::ReplaceClip);
55 | if (m_restrict_path) {
56 | painter->setClipPath(m_path, Qt::IntersectClip);
57 | }
58 | if (m_restrict_points) {
59 | painter->setClipPath(m_points_path, Qt::IntersectClip);
60 | }
61 |
62 | for (const auto &p : m_data_segments) {
63 | painter->setBrush(p.color);
64 | painter->drawPolygon(p.polygon);
65 | }
66 | } else if (m_display_mode == Valeronoi::state::DISPLAY_MODE::DataPoints) {
67 | for (const auto &p : m_data_segments) {
68 | painter->setBrush(p.color);
69 | painter->drawEllipse(p.x - 2, p.y - 2, 4, 4);
70 | }
71 | }
72 |
73 | painter->setClipRect(boundingRect(), Qt::ReplaceClip);
74 | const auto &map = m_robot_map.get_map();
75 | const auto base_y = map.size_y + SCALE_MARGIN;
76 | if (!m_legend.isNull()) {
77 | painter->drawPicture(QPoint(SCALE_MARGIN, base_y), m_legend);
78 | }
79 | }
80 | }
81 |
82 | void MeasurementItem::set_display_mode(
83 | Valeronoi::state::DISPLAY_MODE display_mode) {
84 | m_display_mode = display_mode;
85 | calculate_colors();
86 | }
87 |
88 | void MeasurementItem::set_color_map(
89 | const Valeronoi::util::RGBColorMap *color_map) {
90 | m_color_map = color_map;
91 | calculate_colors();
92 | }
93 |
94 | QColor MeasurementItem::color_value(double normalized_value) const {
95 | auto color = m_color_map->get_color(normalized_value);
96 | return {static_cast(255 * color[0]), static_cast(255 * color[1]),
97 | static_cast(255 * color[2])};
98 | }
99 |
100 | QColor MeasurementItem::get_color(double value) const {
101 | if (m_min == m_max || m_max - m_min == 0 || m_min > m_max || !m_color_map) {
102 | return Qt::black;
103 | }
104 | double normalized = (value - m_min) / (m_max - m_min);
105 | return color_value(normalized);
106 | }
107 |
108 | void MeasurementItem::set_data_segments(const state::DataSegments &segments) {
109 | m_points_path.clear();
110 | m_points_path.setFillRule(Qt::WindingFill);
111 | m_data_segments = segments;
112 | m_min = 0.0;
113 | m_max = -100.0;
114 | m_histogram.clear();
115 | m_histogram_max = 0;
116 | for (const auto &s : m_data_segments) {
117 | m_min = std::min(m_min, s.value);
118 | m_max = std::max(m_max, s.value);
119 | const auto int_value = static_cast(s.value);
120 | m_histogram[int_value] += 1;
121 | m_histogram_max = std::max(m_histogram_max, m_histogram[int_value]);
122 | m_points_path.addRect(s.x - PATH_DISTANCE, s.y - PATH_DISTANCE,
123 | 2 * PATH_DISTANCE, 2 * PATH_DISTANCE);
124 | }
125 | calculate_colors();
126 | }
127 |
128 | void MeasurementItem::calculate_colors() {
129 | for (auto &s : m_data_segments) {
130 | s.color = get_color(s.value);
131 | }
132 | if (m_color_map && m_max > m_min && m_robot_map.is_valid()) {
133 | QPainter painter;
134 | painter.begin(&m_legend);
135 | painter.setFont(m_font);
136 |
137 | painter.setBrush(Qt::black);
138 | painter.setPen(Qt::transparent);
139 | painter.drawRect(0, 0, SCALE_WIDTH + 2 * SCALE_MARGIN,
140 | SCALE_SIZE.height() + 2 * SCALE_MARGIN);
141 |
142 | if (m_histogram_max > 0) {
143 | painter.setPen(Qt::transparent);
144 | const auto int_max = static_cast(m_max);
145 | const auto int_min = static_cast(m_min);
146 | const auto bar_width =
147 | static_cast(SCALE_WIDTH) / (int_max - int_min + 1);
148 | std::for_each(
149 | m_histogram.begin(), m_histogram.end(), [&](const auto values) {
150 | const auto bin = values.first;
151 | const auto count = values.second;
152 | const auto height = SCALE_HISTOGRAM_HEIGHT *
153 | static_cast(count) / m_histogram_max;
154 | const auto x = SCALE_MARGIN + bar_width * (bin - int_min);
155 | auto bin_rect =
156 | QRectF(x, SCALE_MARGIN + SCALE_HISTOGRAM_HEIGHT - height,
157 | bar_width, height);
158 | painter.setBrush(get_color(bin));
159 | painter.drawRect(bin_rect);
160 | });
161 | painter.setBrush(Qt::transparent);
162 | painter.setPen(QPen(Qt::white, 1));
163 | painter.drawRect(SCALE_MARGIN, SCALE_MARGIN, SCALE_WIDTH,
164 | SCALE_HISTOGRAM_HEIGHT);
165 | }
166 |
167 | painter.setPen(Qt::transparent);
168 |
169 | for (int x = 0; x < SCALE_WIDTH; x++) {
170 | painter.setBrush(color_value(static_cast(x) / SCALE_WIDTH));
171 | painter.drawRect(x + SCALE_MARGIN,
172 | 2 * SCALE_MARGIN + SCALE_HISTOGRAM_HEIGHT, 1,
173 | SCALE_BAR_HEIGHT / 3);
174 | }
175 | painter.setBrush(Qt::transparent);
176 | painter.setPen(QPen(Qt::white, 1));
177 | painter.drawRect(SCALE_MARGIN, 2 * SCALE_MARGIN + SCALE_HISTOGRAM_HEIGHT,
178 | SCALE_WIDTH, SCALE_BAR_HEIGHT / 3);
179 | painter.drawText(
180 | SCALE_MARGIN,
181 | 2 * SCALE_MARGIN + SCALE_HISTOGRAM_HEIGHT + SCALE_BAR_HEIGHT / 3,
182 | SCALE_WIDTH / 2, (SCALE_BAR_HEIGHT / 3) * 2, Qt::AlignTop,
183 | QString::number(m_min, 'f', 1).append(" dBm"));
184 | painter.drawText(
185 | SCALE_MARGIN + SCALE_WIDTH / 2,
186 | 2 * SCALE_MARGIN + SCALE_HISTOGRAM_HEIGHT + SCALE_BAR_HEIGHT / 3,
187 | SCALE_WIDTH / 2, (SCALE_BAR_HEIGHT / 3) * 2,
188 | Qt::AlignTop | Qt::AlignRight,
189 | QString::number(m_max, 'f', 1).append(" dBm"));
190 |
191 | painter.end();
192 | }
193 | update();
194 | }
195 |
196 | void MeasurementItem::set_restrict_path(bool enabled) {
197 | m_restrict_path = enabled;
198 | update();
199 | }
200 |
201 | void MeasurementItem::set_restrict_path(const QPainterPath &path) {
202 | m_path = path;
203 | m_path.setFillRule(Qt::WindingFill);
204 | m_restrict_path = true;
205 | update();
206 | }
207 |
208 | void MeasurementItem::set_restrict_points(bool enabled) {
209 | m_restrict_points = enabled;
210 | update();
211 | }
212 |
213 | QRectF MeasurementItem::boundingRect() const {
214 | auto rect = MapBasedItem::boundingRect();
215 | if (!m_robot_map.is_valid()) {
216 | return rect;
217 | }
218 | if (rect.width() < SCALE_WIDTH + SCALE_MARGIN) {
219 | rect += QMarginsF(0, 0, SCALE_WIDTH + SCALE_MARGIN, 0);
220 | }
221 | return rect + QMarginsF(0, 0, 0, SCALE_SIZE.height() + 4 * SCALE_MARGIN);
222 | }
223 |
224 | } // namespace Valeronoi::gui::graphics_item
225 |
--------------------------------------------------------------------------------
/src/gui/graphics_item/measurement_item.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_GRAPHICS_ITEM_MEASUREMENT_ITEM_H
19 | #define VALERONOI_GUI_GRAPHICS_ITEM_MEASUREMENT_ITEM_H
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | #include "../../state/measurements.h"
26 | #include "../../state/robot_map.h"
27 | #include "../../state/state.h"
28 | #include "../../util/colormap.h"
29 | #include "map_based_item.h"
30 |
31 | namespace Valeronoi::gui::graphics_item {
32 |
33 | class MeasurementItem : public MapBasedItem {
34 | public:
35 | explicit MeasurementItem(const Valeronoi::state::RobotMap &robot_map,
36 | QGraphicsItem *parent = nullptr);
37 |
38 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
39 | QWidget *widget) override;
40 |
41 | void set_data_segments(const Valeronoi::state::DataSegments &segments);
42 |
43 | void set_display_mode(Valeronoi::state::DISPLAY_MODE display_mode);
44 |
45 | void set_color_map(const Valeronoi::util::RGBColorMap *color_map);
46 |
47 | void set_restrict_path(bool enabled);
48 |
49 | void set_restrict_path(const QPainterPath &path);
50 |
51 | void set_restrict_points(bool enabled);
52 |
53 | [[nodiscard]] QRectF boundingRect() const override;
54 |
55 | private:
56 | void calculate_colors();
57 |
58 | [[nodiscard]] QColor get_color(double value) const;
59 |
60 | [[nodiscard]] QColor color_value(double normalized_value) const;
61 |
62 | double m_min{0.0}, m_max{0.0};
63 | std::unordered_map m_histogram;
64 | int m_histogram_max{0};
65 |
66 | const Valeronoi::util::RGBColorMap *m_color_map{nullptr};
67 |
68 | Valeronoi::state::DISPLAY_MODE m_display_mode{
69 | Valeronoi::state::DISPLAY_MODE::Voronoi};
70 |
71 | Valeronoi::state::DataSegments m_data_segments;
72 |
73 | bool m_restrict_path{true}, m_restrict_points{true};
74 | QPainterPath m_path, m_points_path;
75 | QFont m_font;
76 | QPicture m_legend;
77 | };
78 |
79 | } // namespace Valeronoi::gui::graphics_item
80 |
81 | #endif
82 |
--------------------------------------------------------------------------------
/src/gui/widget/display_widget.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_GUI_WIDGET_DISPLAY_WIDGET_H
19 | #define VALERONOI_GUI_WIDGET_DISPLAY_WIDGET_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include "../../state/measurements.h"
28 | #include "../../state/robot_map.h"
29 | #include "../../util/colormap.h"
30 | #include "../../util/segment_generator.h"
31 | #include "../graphics_item/entity_item.h"
32 | #include "../graphics_item/floor_item.h"
33 | #include "../graphics_item/map_item.h"
34 | #include "../graphics_item/measurement_item.h"
35 |
36 | namespace Valeronoi::gui::widget {
37 |
38 | class DisplayWidget : public QGraphicsView {
39 | Q_OBJECT
40 | public:
41 | explicit DisplayWidget(const Valeronoi::state::RobotMap &robot_map,
42 | const Valeronoi::state::Measurements &measurements,
43 | QWidget *parent);
44 |
45 | [[nodiscard]] QColor get_background_color() const;
46 |
47 | void set_background_color(QColor color);
48 |
49 | [[nodiscard]] QColor get_wall_color() const;
50 |
51 | void set_wall_color(QColor color);
52 |
53 | void set_color_map(const Valeronoi::util::RGBColorMap *color_map);
54 |
55 | void set_floor(bool enabled, QColor color);
56 |
57 | [[nodiscard]] bool get_floor_enabled() const;
58 |
59 | [[nodiscard]] QColor get_floor_color() const;
60 |
61 | void set_entities(bool enabled);
62 |
63 | [[nodiscard]] bool get_entities_enabled() const;
64 |
65 | [[nodiscard]] qreal get_zoom_factor() const;
66 |
67 | void set_opengl(bool enabled);
68 |
69 | [[nodiscard]] bool get_opengl() const;
70 |
71 | void set_antialiasing(bool enabled);
72 |
73 | [[nodiscard]] bool get_antialiasing() const;
74 |
75 | void set_restrict_floor(bool enabled);
76 |
77 | [[nodiscard]] bool get_restrict_floor() const;
78 |
79 | void set_restrict_path(bool enabled);
80 |
81 | [[nodiscard]] bool get_restrict_path() const;
82 |
83 | [[nodiscard]] int get_simplify() const;
84 |
85 | [[nodiscard]] int get_wifi_id_filter() const;
86 |
87 | signals:
88 | void signal_relocate(int x, int y);
89 |
90 | public slots:
91 | void slot_map_updated();
92 |
93 | void slot_measurements_updated();
94 |
95 | void slot_set_display_mode(int display_mode);
96 |
97 | void slot_update_map_rect();
98 |
99 | void slot_set_simplify(int value);
100 |
101 | void slot_set_wifi_id_filter(int wifi_id_filter);
102 |
103 | protected:
104 | void wheelEvent(QWheelEvent *event) override;
105 | void paintEvent(QPaintEvent *event) override;
106 |
107 | private:
108 | void zoom_by(qreal factor);
109 |
110 | QColor m_background_color, m_wall_color, m_floor_color;
111 | bool m_draw_floor{true}, m_draw_entities{true}, m_use_opengl{false},
112 | m_antialiasing{true}, m_restrict_floor{true}, m_restrict_path{true};
113 | int m_simplify{1}, m_wifi_id_filter{-1};
114 | const Valeronoi::util::RGBColorMap *m_color_map{nullptr};
115 | Valeronoi::util::SegmentGenerator m_segment_generator;
116 |
117 | Valeronoi::state::DISPLAY_MODE m_display_mode{
118 | Valeronoi::state::DISPLAY_MODE::Voronoi};
119 |
120 | const Valeronoi::state::Measurements &m_measurements;
121 |
122 | Valeronoi::gui::graphics_item::MapItem *m_map_item;
123 | Valeronoi::gui::graphics_item::FloorItem *m_floor_item;
124 | Valeronoi::gui::graphics_item::EntityItem *m_entity_item;
125 | Valeronoi::gui::graphics_item::MeasurementItem *m_measurement_item;
126 |
127 | QPainterPath m_floor_path;
128 | };
129 |
130 | } // namespace Valeronoi::gui::widget
131 |
132 | #endif
133 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #include "config.h"
24 | #include "state/state.h"
25 | #include "util/log_helper.h"
26 | #include "valeronoi.h"
27 |
28 | int main(int argc, char **argv) {
29 | qInstallMessageHandler(Valeronoi::util::log_handler);
30 |
31 | QApplication app(argc, argv);
32 | QCoreApplication::setOrganizationName("ccoors");
33 | QCoreApplication::setOrganizationDomain("ccoors.de");
34 | QCoreApplication::setApplicationName("Valeronoi");
35 | QCoreApplication::setApplicationVersion(VALERONOI_VERSION);
36 |
37 | Q_INIT_RESOURCE(valeronoi);
38 | QFontDatabase::addApplicationFont(":/res/SourceCodePro-Regular.otf");
39 | QApplication::setWindowIcon(QIcon(":/res/valeronoi.png"));
40 |
41 | qRegisterMetaType();
42 |
43 | QCommandLineParser parser;
44 | parser.setApplicationDescription(
45 | "A WiFi signal strength mapping companion for Valetudo");
46 | parser.addHelpOption();
47 | parser.addVersionOption();
48 | parser.addPositionalArgument("file", "The file to open.");
49 | parser.process(app);
50 |
51 | Valeronoi::ValeronoiWindow valeronoi;
52 | if (!parser.positionalArguments().isEmpty()) {
53 | if (!valeronoi.load_file(parser.positionalArguments().value(0))) {
54 | return 1;
55 | }
56 | }
57 | valeronoi.show();
58 |
59 | return app.exec();
60 | }
61 |
--------------------------------------------------------------------------------
/src/res/SourceCodePro-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/src/res/SourceCodePro-Regular.otf
--------------------------------------------------------------------------------
/src/res/valeronoi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccoors/Valeronoi/d4ffe5d01598f2c792580b5d06937028bf624cab/src/res/valeronoi.png
--------------------------------------------------------------------------------
/src/robot/api/sse.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "sse.h"
19 |
20 | namespace Valeronoi::robot::api {
21 |
22 | SSEConnection::SSEConnection() {
23 | m_reconnect_timer.setSingleShot(true);
24 | connect(&m_reconnect_timer, &QTimer::timeout, this,
25 | &SSEConnection::slot_make_request);
26 | }
27 |
28 | void SSEConnection::set_connection_configuration(
29 | const ConnectionConfiguration &conf) {
30 | m_connection_configuration = conf;
31 | }
32 |
33 | void SSEConnection::set_initial_url(const QUrl &url) { m_initial_url = url; }
34 |
35 | void SSEConnection::set_url(const QUrl &url) { m_url = url; }
36 |
37 | QString SSEConnection::current_data() const { return m_current_data; }
38 |
39 | void SSEConnection::slot_connect() {
40 | if (m_connected) {
41 | return;
42 | }
43 |
44 | if (!m_initial_url.isEmpty()) {
45 | qDebug() << "Making initial request";
46 | m_initial_current_data = "";
47 | m_current_data = "";
48 | QNetworkRequest request = prepare_request(m_initial_url);
49 |
50 | auto reply = m_qnam.get(request);
51 | connect(reply, &QNetworkReply::readyRead, this, [=]() {
52 | qDebug() << "Received initial map data";
53 | auto buffer = reply->readAll();
54 | m_initial_current_data.append(buffer);
55 | });
56 | connect(reply, &QNetworkReply::errorOccurred, this,
57 | [=](QNetworkReply::NetworkError error) {
58 | if (error != QNetworkReply::NetworkError::NoError) {
59 | qDebug().nospace()
60 | << "Initial request error: " << reply->errorString();
61 | }
62 | });
63 | connect(reply, &QNetworkReply::finished, this, [=]() {
64 | if (!m_initial_current_data.isEmpty() && m_current_data.isEmpty()) {
65 | m_current_data = m_initial_current_data;
66 | emit signal_data_updated();
67 | }
68 |
69 | reply->deleteLater();
70 | });
71 | }
72 |
73 | qDebug() << "Starting SSE request";
74 | m_connected = true;
75 | slot_make_request();
76 | }
77 |
78 | void SSEConnection::slot_ready_read() {
79 | if (!m_reply) {
80 | // Should not happen
81 | return;
82 | }
83 | // m_reply->readAll returns chunked data, so we put it back together and
84 | // parse it according to https://www.w3.org/TR/eventsource/
85 | const auto buffer = m_reply->readAll();
86 | qDebug().nospace() << "Received SSE segment: size " << buffer.size();
87 | QStringList lines = QString(buffer).split("\n");
88 |
89 | for (const QString &raw_line : lines) {
90 | QString line = raw_line.simplified();
91 |
92 | switch (m_parser_state) {
93 | case ParserState::IDLE:
94 | if (line.startsWith(":")) {
95 | continue;
96 | } else if (line.startsWith("event: ")) {
97 | m_event_type = line.right(line.size() - 7);
98 | } else if (line.startsWith("data: ") && m_event_type == m_event) {
99 | m_data_buffer = line.right(line.size() - 6);
100 | m_parser_state = ParserState::DATA;
101 | }
102 | break;
103 | case ParserState::DATA:
104 | if (line.isEmpty()) {
105 | m_parser_state = ParserState::IDLE;
106 | m_current_data = m_data_buffer;
107 | emit signal_data_updated();
108 | } else {
109 | m_data_buffer.append(line);
110 | }
111 | }
112 | }
113 | }
114 |
115 | void SSEConnection::slot_disconnect() {
116 | if (!m_connected) {
117 | return;
118 | }
119 | qDebug() << "SSE connection closed";
120 | m_connected = false;
121 | if (m_reply) {
122 | m_reply->abort();
123 | m_reply = nullptr;
124 | }
125 | }
126 |
127 | void SSEConnection::slot_stream_finished() {
128 | qDebug() << "SSE connection finished";
129 | m_reply->deleteLater();
130 | m_reply = nullptr;
131 | if (m_connected) {
132 | m_reconnect_timer.start(RECONNECT_TIMER);
133 | }
134 | }
135 |
136 | void SSEConnection::slot_make_request() {
137 | if (!m_connected) {
138 | return;
139 | }
140 | QNetworkRequest request = prepare_request(m_url);
141 |
142 | m_reply = m_qnam.get(request);
143 | connect(m_reply, &QNetworkReply::readyRead, this,
144 | &SSEConnection::slot_ready_read);
145 | connect(m_reply, &QNetworkReply::finished, this,
146 | &SSEConnection::slot_stream_finished);
147 | }
148 |
149 | QNetworkRequest SSEConnection::prepare_request(const QUrl &url) const {
150 | QNetworkRequest request(m_connection_configuration.m_url.resolved(url));
151 | m_connection_configuration.prepare_request(request);
152 | request.setRawHeader("Accept", "text/event-stream");
153 | return request;
154 | }
155 |
156 | void SSEConnection::set_event(const QString &event) { m_event = event; }
157 |
158 | } // namespace Valeronoi::robot::api
159 |
--------------------------------------------------------------------------------
/src/robot/api/sse.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_ROBOT_API_SSE_H
19 | #define VALERONOI_ROBOT_API_SSE_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include "../connection_configuration.h"
34 |
35 | namespace Valeronoi::robot::api {
36 |
37 | constexpr const std::chrono::milliseconds RECONNECT_TIMER{2000};
38 |
39 | enum class ParserState { IDLE = 0, DATA };
40 |
41 | class SSEConnection : public QObject {
42 | Q_OBJECT
43 | public:
44 | SSEConnection();
45 |
46 | void set_connection_configuration(const ConnectionConfiguration &conf);
47 |
48 | void set_initial_url(const QUrl &url);
49 |
50 | void set_url(const QUrl &url);
51 |
52 | void set_event(const QString &event);
53 |
54 | [[nodiscard]] QString current_data() const;
55 |
56 | public slots:
57 | void slot_connect();
58 |
59 | void slot_disconnect();
60 |
61 | signals:
62 | void signal_data_updated();
63 |
64 | private slots:
65 | void slot_ready_read();
66 |
67 | void slot_stream_finished();
68 |
69 | void slot_make_request();
70 |
71 | private:
72 | QNetworkRequest prepare_request(const QUrl &url) const;
73 |
74 | bool m_connected{false};
75 | QString m_event, m_data_buffer, m_initial_current_data, m_current_data,
76 | m_event_type;
77 | ParserState m_parser_state{ParserState::IDLE};
78 | QTimer m_reconnect_timer;
79 | ConnectionConfiguration m_connection_configuration;
80 | QUrl m_initial_url, m_url;
81 | QNetworkReply *m_reply{nullptr};
82 | QNetworkAccessManager m_qnam;
83 | };
84 |
85 | } // namespace Valeronoi::robot::api
86 |
87 | #endif
88 |
--------------------------------------------------------------------------------
/src/robot/api/valetudo_v2.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "valetudo_v2.h"
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | namespace Valeronoi::robot::api::v2 {
26 |
27 | const QUrl VALETUDO_VERSION = QUrl("/api/v2/valetudo/version");
28 | const QUrl ROBOT_INFO = QUrl("/api/v2/robot");
29 | const QUrl ROBOT_STATE = QUrl("/api/v2/robot/state");
30 | const QUrl ROBOT_CAPABILITIES_INFO = QUrl("/api/v2/robot/capabilities");
31 | const QUrl ROBOT_MAP = QUrl("/api/v2/robot/state/map");
32 | const QUrl ROBOT_MAP_SSE = QUrl("/api/v2/robot/state/map/sse");
33 |
34 | const QList ROBOT_INIT_URLS = {VALETUDO_VERSION, ROBOT_INFO, ROBOT_STATE,
35 | ROBOT_CAPABILITIES_INFO};
36 |
37 | ValetudoAPI::ValetudoAPI() {
38 | m_map_connection.set_initial_url(ROBOT_MAP);
39 | m_map_connection.set_url(ROBOT_MAP_SSE);
40 | m_map_connection.set_event("MapUpdated");
41 | connect(&m_map_connection,
42 | &Valeronoi::robot::api::SSEConnection::signal_data_updated, this,
43 | &ValetudoAPI::slot_map_updated);
44 | }
45 |
46 | void ValetudoAPI::set_connection_configuration(
47 | const ConnectionConfiguration &conf) {
48 | m_connection_configuration = conf;
49 | m_map_connection.set_connection_configuration(conf);
50 | }
51 |
52 | const RobotInformation *ValetudoAPI::get_information() const {
53 | return &m_robot_information;
54 | }
55 |
56 | QString ValetudoAPI::get_error() const { return m_error_message; }
57 |
58 | bool ValetudoAPI::is_connected() const { return m_connected; }
59 |
60 | bool ValetudoAPI::is_connecting() const { return m_connecting; }
61 |
62 | void ValetudoAPI::slot_connect() {
63 | if (m_connected || m_connecting) {
64 | return;
65 | }
66 | m_connecting = true;
67 | m_connecting_step = 0;
68 | m_connection_responses.clear();
69 | m_error_message = "";
70 | emit signal_connecting();
71 | next_connection_step();
72 | }
73 |
74 | void ValetudoAPI::slot_disconnect() {
75 | if (!m_connected && !m_connecting) {
76 | return;
77 | }
78 | m_connected = false;
79 | m_connecting = false;
80 | m_map_connection.slot_disconnect();
81 | emit signal_connection_ended();
82 | }
83 |
84 | void ValetudoAPI::next_connection_step() {
85 | if (m_connecting_step == ROBOT_INIT_URLS.size()) {
86 | // We're done
87 | m_connecting = false;
88 | m_connected = true;
89 |
90 | // Parse responses from connection sequence
91 | const auto valetudo_version =
92 | m_connection_responses[0].object()["release"].toString();
93 | m_robot_information.m_valetudo_version = valetudo_version;
94 |
95 | const auto robot_info = m_connection_responses[1].object();
96 | m_robot_information.m_manufacturer = robot_info["manufacturer"].toString();
97 | m_robot_information.m_model_name = robot_info["modelName"].toString();
98 | m_robot_information.m_implementation =
99 | robot_info["implementation"].toString();
100 |
101 | const auto robot_state = m_connection_responses[2].object();
102 | m_robot_information.m_attributes = robot_state["attributes"].toArray();
103 |
104 | const auto robot_capabilities = m_connection_responses[3].array();
105 | m_robot_information.m_capabilities.clear();
106 | for (const auto &&c : robot_capabilities) {
107 | m_robot_information.m_capabilities.push_back(c.toString());
108 | }
109 |
110 | m_map_connection.slot_connect();
111 | emit signal_connected();
112 | return;
113 | }
114 |
115 | emit signal_connecting_step(static_cast(m_connecting_step) /
116 | ROBOT_INIT_URLS.size());
117 | const auto next_url = ROBOT_INIT_URLS[m_connecting_step];
118 | auto request =
119 | QNetworkRequest(m_connection_configuration.m_url.resolved(next_url));
120 | m_connection_configuration.prepare_request(request);
121 | auto reply = m_qnam.get(request);
122 | connect(reply, &QNetworkReply::finished, this, [=]() {
123 | if (m_connecting) {
124 | if (reply->error() != QNetworkReply::NetworkError::NoError) {
125 | m_error_message = reply->errorString();
126 | emit signal_connection_error();
127 | slot_disconnect();
128 | } else {
129 | auto resp_data = reply->readAll();
130 | QJsonParseError error;
131 | auto json = QJsonDocument::fromJson(resp_data, &error);
132 | if (json.isNull()) {
133 | // Invalid JSON received
134 | m_error_message = error.errorString();
135 | emit signal_connection_error();
136 | slot_disconnect();
137 | }
138 | m_connection_responses.push_back(json);
139 | next_connection_step();
140 | }
141 | }
142 | reply->deleteLater();
143 | });
144 |
145 | m_connecting_step++;
146 | }
147 |
148 | QNetworkReply *ValetudoAPI::request(const QString &verb, const QUrl &url,
149 | bool disconnect_on_failure, bool gc,
150 | const QByteArray *data) {
151 | qDebug().nospace() << "Robot request: " << verb << " to " << url;
152 | if (!m_connected) {
153 | return nullptr;
154 | }
155 | auto request =
156 | QNetworkRequest(m_connection_configuration.m_url.resolved(url));
157 | m_connection_configuration.prepare_request(request);
158 | if (data != nullptr) {
159 | request.setRawHeader("Content-Type", "application/json");
160 | }
161 | auto response = data != nullptr
162 | ? m_qnam.sendCustomRequest(request, verb.toUtf8(), *data)
163 | : m_qnam.sendCustomRequest(request, verb.toUtf8());
164 | if (disconnect_on_failure) {
165 | connect(response, &QNetworkReply::errorOccurred, this,
166 | [=](QNetworkReply::NetworkError error) {
167 | if (error != QNetworkReply::NetworkError::NoError) {
168 | m_error_message = response->errorString();
169 | emit signal_connection_error();
170 | slot_disconnect();
171 | }
172 | });
173 | }
174 | if (gc) {
175 | connect(response, &QNetworkReply::finished, this,
176 | [=]() { response->deleteLater(); });
177 | }
178 | return response;
179 | }
180 |
181 | void ValetudoAPI::slot_map_updated() { emit signal_map_updated(); }
182 |
183 | QString ValetudoAPI::get_map_data() const {
184 | return m_map_connection.current_data();
185 | }
186 |
187 | static QJsonDocument gen_document(const QString &action) {
188 | auto ret = QJsonDocument();
189 | auto object = QJsonObject();
190 | object.insert("action", action);
191 | ret.setObject(object);
192 | return ret;
193 | }
194 |
195 | void ValetudoAPI::send_command(Valeronoi::robot::BASIC_COMMANDS command) {
196 | if (!m_connected) {
197 | return;
198 | }
199 | switch (command) {
200 | case BASIC_COMMANDS::START: {
201 | auto data = gen_document("start").toJson();
202 | request("PUT", QUrl("/api/v2/robot/capabilities/BasicControlCapability"),
203 | false, true, &data);
204 | } break;
205 | case BASIC_COMMANDS::PAUSE: {
206 | auto data = gen_document("pause").toJson();
207 | request("PUT", QUrl("/api/v2/robot/capabilities/BasicControlCapability"),
208 | false, true, &data);
209 | } break;
210 | case BASIC_COMMANDS::STOP: {
211 | auto data = gen_document("stop").toJson();
212 | request("PUT", QUrl("/api/v2/robot/capabilities/BasicControlCapability"),
213 | false, true, &data);
214 | } break;
215 | case BASIC_COMMANDS::HOME: {
216 | auto data = gen_document("home").toJson();
217 | request("PUT", QUrl("/api/v2/robot/capabilities/BasicControlCapability"),
218 | false, true, &data);
219 | } break;
220 | case BASIC_COMMANDS::LOCATE: {
221 | auto data = gen_document("locate").toJson();
222 | request("PUT", QUrl("/api/v2/robot/capabilities/LocateCapability"), false,
223 | true, &data);
224 | }
225 | }
226 | }
227 |
228 | void ValetudoAPI::relocate(int x, int y) {
229 | if (!m_connected) {
230 | QMessageBox::information(nullptr, "Valeronoi",
231 | tr("Not connected to a robot."));
232 | return;
233 | }
234 | if (!m_robot_information.m_capabilities.contains("GoToLocationCapability")) {
235 | QMessageBox::information(
236 | nullptr, "Valeronoi",
237 | tr("This robot does not support the GoToLocationCapability."));
238 | return;
239 | }
240 | auto document = QJsonDocument();
241 | auto object = QJsonObject();
242 | object.insert("action", "goto");
243 | auto coords = QJsonObject();
244 | coords.insert("x", x);
245 | coords.insert("y", y);
246 | object.insert("coordinates", coords);
247 | document.setObject(object);
248 | auto data = document.toJson();
249 | request("PUT", QUrl("/api/v2/robot/capabilities/GoToLocationCapability"),
250 | false, true, &data);
251 | }
252 |
253 | } // namespace Valeronoi::robot::api::v2
254 |
--------------------------------------------------------------------------------
/src/robot/api/valetudo_v2.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_ROBOT_API_VALETUDO_V2_H
19 | #define VALERONOI_ROBOT_API_VALETUDO_V2_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #include "../commands.h"
33 | #include "../connection_configuration.h"
34 | #include "../robot_information.h"
35 | #include "sse.h"
36 |
37 | namespace Valeronoi::robot::api::v2 {
38 |
39 | const QUrl ROBOT_WIFI_CAPABILITY =
40 | QUrl("/api/v2/robot/capabilities/WifiConfigurationCapability");
41 |
42 | class ValetudoAPI : public QObject {
43 | Q_OBJECT
44 | public:
45 | ValetudoAPI();
46 |
47 | void set_connection_configuration(const ConnectionConfiguration &conf);
48 |
49 | [[nodiscard]] const RobotInformation *get_information() const;
50 |
51 | [[nodiscard]] QString get_error() const;
52 |
53 | [[nodiscard]] bool is_connected() const;
54 |
55 | [[nodiscard]] bool is_connecting() const;
56 |
57 | QNetworkReply *request(const QString &verb, const QUrl &url,
58 | bool disconnect_on_failure = false, bool gc = false,
59 | const QByteArray *data = nullptr);
60 |
61 | [[nodiscard]] QString get_map_data() const;
62 |
63 | void send_command(Valeronoi::robot::BASIC_COMMANDS command);
64 |
65 | void relocate(int x, int y);
66 |
67 | public slots:
68 | void slot_connect();
69 |
70 | void slot_disconnect();
71 |
72 | signals:
73 | void signal_connecting();
74 |
75 | void signal_connecting_step(float value);
76 |
77 | void signal_connected();
78 |
79 | void signal_connection_error();
80 |
81 | void signal_connection_ended();
82 |
83 | void signal_map_updated();
84 |
85 | private slots:
86 | void slot_map_updated();
87 |
88 | private:
89 | void next_connection_step();
90 |
91 | bool m_connected{false}, m_connecting{false};
92 | int m_connecting_step{0};
93 | RobotInformation m_robot_information;
94 | ConnectionConfiguration m_connection_configuration;
95 |
96 | QString m_error_message;
97 |
98 | QNetworkAccessManager m_qnam;
99 | QList m_connection_responses;
100 |
101 | Valeronoi::robot::api::SSEConnection m_map_connection;
102 | };
103 |
104 | } // namespace Valeronoi::robot::api::v2
105 |
106 | #endif
107 |
--------------------------------------------------------------------------------
/src/robot/commands.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_ROBOT_COMMANDS_H
19 | #define VALERONOI_ROBOT_COMMANDS_H
20 |
21 | namespace Valeronoi::robot {
22 |
23 | enum class BASIC_COMMANDS { START, PAUSE, STOP, HOME, LOCATE };
24 |
25 | }
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/src/robot/connection_configuration.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "connection_configuration.h"
19 |
20 | #include
21 |
22 | #include "config.h"
23 |
24 | namespace Valeronoi::robot {
25 |
26 | void ConnectionConfiguration::read_settings() {
27 | QSettings settings;
28 | m_url = settings.value("robot/url", "").toUrl();
29 | m_auth = settings.value("robot/auth/enabled", false).toBool();
30 | m_username = settings.value("robot/auth/username", "").toString();
31 | m_password = settings.value("robot/auth/password", "").toString();
32 | }
33 |
34 | ConnectionConfiguration &ConnectionConfiguration::operator=(
35 | const ConnectionConfiguration &other) {
36 | if (this != &other) {
37 | m_url = other.m_url;
38 | m_auth = other.m_auth;
39 | m_username = other.m_username;
40 | m_password = other.m_password;
41 | }
42 | return *this;
43 | }
44 |
45 | bool ConnectionConfiguration::is_valid() const {
46 | return !m_url.isEmpty() && m_url.isValid();
47 | }
48 |
49 | void ConnectionConfiguration::prepare_request(QNetworkRequest &r) const {
50 | r.setMaximumRedirectsAllowed(10); // Should not be needed anyway
51 | r.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
52 | QNetworkRequest::AlwaysNetwork);
53 | r.setTransferTimeout(5000); // TODO configurable?
54 | r.setHeader(QNetworkRequest::UserAgentHeader, "Valeronoi/" VALERONOI_VERSION);
55 | if (m_auth) {
56 | QString user_pw = m_username + ":" + m_password;
57 | QByteArray data = user_pw.toLocal8Bit().toBase64();
58 | QString header_data = "Basic " + data;
59 | r.setRawHeader("Authorization", header_data.toLocal8Bit());
60 | }
61 | }
62 |
63 | } // namespace Valeronoi::robot
64 |
--------------------------------------------------------------------------------
/src/robot/connection_configuration.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_ROBOT_CONNECTION_INFORMATION_H
19 | #define VALERONOI_ROBOT_CONNECTION_INFORMATION_H
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | namespace Valeronoi::robot {
26 |
27 | struct ConnectionConfiguration {
28 | QUrl m_url;
29 | bool m_auth;
30 | QString m_username, m_password;
31 |
32 | void read_settings();
33 |
34 | [[nodiscard]] bool is_valid() const;
35 |
36 | ConnectionConfiguration& operator=(const ConnectionConfiguration& other);
37 |
38 | void prepare_request(QNetworkRequest& r) const;
39 | };
40 |
41 | } // namespace Valeronoi::robot
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/robot/robot.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "robot.h"
19 |
20 | #include "../gui/dialog/robot_config.h"
21 |
22 | namespace Valeronoi::robot {
23 |
24 | Robot::Robot() {
25 | // Reroute signals from API
26 | connect(&m_api, &Valeronoi::robot::api::v2::ValetudoAPI::signal_connecting,
27 | this, [=]() { emit signal_connecting(); });
28 | connect(&m_api,
29 | &Valeronoi::robot::api::v2::ValetudoAPI::signal_connecting_step, this,
30 | [=](float value) { emit signal_connecting_step(value); });
31 | connect(&m_api, &Valeronoi::robot::api::v2::ValetudoAPI::signal_connected,
32 | this, [=]() { emit signal_connected(); });
33 | connect(&m_api,
34 | &Valeronoi::robot::api::v2::ValetudoAPI::signal_connection_error,
35 | this, [=]() { emit signal_connection_error(); });
36 | connect(&m_api,
37 | &Valeronoi::robot::api::v2::ValetudoAPI::signal_connection_ended,
38 | this, [=]() { emit signal_connection_ended(); });
39 | connect(&m_api, &Valeronoi::robot::api::v2::ValetudoAPI::signal_map_updated,
40 | this, [=]() { emit signal_map_updated(); });
41 | connect(&m_wifi_timer, &QTimer::timeout, this, &Robot::slot_get_wifi);
42 | m_wifi_timer.setTimerType(Qt::CoarseTimer);
43 | m_wifi_timer.setSingleShot(false);
44 | }
45 |
46 | void Robot::set_connection_configuration(const ConnectionConfiguration &conf) {
47 | m_api.set_connection_configuration(conf);
48 | }
49 |
50 | QString Robot::get_error() const { return m_api.get_error(); }
51 |
52 | bool Robot::is_connected() const { return m_api.is_connected(); }
53 |
54 | bool Robot::is_connecting() const { return m_api.is_connecting(); }
55 |
56 | const RobotInformation *Robot::get_information() const {
57 | return m_api.get_information();
58 | }
59 |
60 | void Robot::slot_connect() {
61 | m_current_wifi_connection = WifiInformation();
62 | m_api.slot_connect();
63 | }
64 |
65 | void Robot::slot_disconnect() {
66 | m_api.slot_disconnect();
67 | m_current_wifi_connection = WifiInformation();
68 | }
69 |
70 | void Robot::slot_subscribe_wifi(double interval) {
71 | m_wifi_timer.start(static_cast(1000 * interval));
72 | }
73 |
74 | void Robot::slot_stop_wifi_subscription() { m_wifi_timer.stop(); }
75 |
76 | void Robot::slot_get_wifi() {
77 | if (is_connected()) {
78 | qDebug() << "Making WiFi Request";
79 | auto reply =
80 | m_api.request("GET", Valeronoi::robot::api::v2::ROBOT_WIFI_CAPABILITY);
81 | connect(reply, &QNetworkReply::finished, this, [=]() {
82 | auto resp_data = reply->readAll();
83 | reply->deleteLater();
84 | QJsonParseError error{};
85 | const auto json = QJsonDocument::fromJson(resp_data, &error);
86 | if (json.isNull()) {
87 | qDebug() << "Invalid JSON:" << error.errorString();
88 | return;
89 | }
90 |
91 | const auto response_class = json.object()["__class"].toString();
92 | if (response_class == "ValetudoWifiStatus" ||
93 | response_class == "ValetudoWifiConfiguration") {
94 | const QJsonObject details_object = json.object()["details"].toObject();
95 | const WifiInformation wifi_info(details_object);
96 | if (wifi_info.bssid() != m_current_wifi_connection.bssid()) {
97 | m_current_wifi_connection = wifi_info;
98 | emit signal_current_wifi_updated(wifi_info);
99 | }
100 | if (wifi_info.has_valid_signal()) {
101 | emit signal_wifi_info_updated(wifi_info);
102 | } else {
103 | qDebug()
104 | << "Message did not contain a valid signal strength, ignoring";
105 | }
106 | } else {
107 | qDebug().nospace() << "Received unexpected JSON object of class '"
108 | << response_class << "', ignoring";
109 | }
110 | });
111 | }
112 | }
113 |
114 | QString Robot::get_map_data() const { return m_api.get_map_data(); }
115 |
116 | void Robot::send_command(BASIC_COMMANDS command) {
117 | m_api.send_command(command);
118 | }
119 |
120 | void Robot::slot_relocate(int x, int y) { m_api.relocate(x, y); }
121 |
122 | } // namespace Valeronoi::robot
123 |
--------------------------------------------------------------------------------
/src/robot/robot.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_ROBOT_ROBOT_H
19 | #define VALERONOI_ROBOT_ROBOT_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #include "api/valetudo_v2.h"
29 | #include "commands.h"
30 | #include "connection_configuration.h"
31 | #include "robot_information.h"
32 | #include "wifi_information.h"
33 |
34 | namespace Valeronoi::robot {
35 |
36 | class Robot : public QObject {
37 | Q_OBJECT
38 | public:
39 | Robot();
40 |
41 | void set_connection_configuration(const ConnectionConfiguration &conf);
42 |
43 | [[nodiscard]] const RobotInformation *get_information() const;
44 |
45 | [[nodiscard]] QString get_error() const;
46 |
47 | [[nodiscard]] bool is_connected() const;
48 |
49 | [[nodiscard]] bool is_connecting() const;
50 |
51 | [[nodiscard]] QString get_map_data() const;
52 |
53 | void send_command(BASIC_COMMANDS command);
54 |
55 | public slots:
56 | void slot_connect();
57 |
58 | void slot_disconnect();
59 |
60 | void slot_subscribe_wifi(double interval);
61 |
62 | void slot_stop_wifi_subscription();
63 |
64 | void slot_relocate(int x, int y);
65 |
66 | signals:
67 | void signal_connecting();
68 |
69 | void signal_connecting_step(float value); // 0.0 - 1.0
70 |
71 | void signal_connected();
72 |
73 | void signal_connection_error();
74 |
75 | void signal_connection_ended();
76 |
77 | void signal_map_updated();
78 |
79 | void signal_wifi_info_updated(WifiInformation wifi_info);
80 |
81 | void signal_current_wifi_updated(WifiInformation wifi_info);
82 |
83 | private slots:
84 | void slot_get_wifi();
85 |
86 | private:
87 | WifiInformation m_current_wifi_connection;
88 | QTimer m_wifi_timer;
89 | Valeronoi::robot::api::v2::ValetudoAPI m_api;
90 | };
91 |
92 | } // namespace Valeronoi::robot
93 |
94 | #endif
95 |
--------------------------------------------------------------------------------
/src/robot/robot_information.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include "robot_information.h"
20 |
21 | namespace Valeronoi::robot {
22 |
23 | QJsonObject RobotInformation::get_attribute(const QString &class_name,
24 | const QString &type,
25 | const QString &sub_type) const {
26 | for (const auto &&attr : m_attributes) {
27 | auto attribute = attr.toObject();
28 | if (!class_name.isEmpty() &&
29 | class_name != attribute["__class"].toString()) {
30 | continue;
31 | }
32 | if (!type.isEmpty() && type != attribute["type"].toString()) {
33 | continue;
34 | }
35 | if (!sub_type.isEmpty() && type != attribute["subType"].toString()) {
36 | continue;
37 | }
38 | return attribute;
39 | }
40 | return QJsonObject();
41 | }
42 |
43 | } // namespace Valeronoi::robot
44 |
--------------------------------------------------------------------------------
/src/robot/robot_information.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALETUDO_ROBOT_ROBOT_INFORMATION_H
19 | #define VALETUDO_ROBOT_ROBOT_INFORMATION_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | namespace Valeronoi::robot {
27 |
28 | struct RobotInformation {
29 | QString m_valetudo_version;
30 | QString m_manufacturer, m_model_name, m_implementation;
31 | QStringList m_capabilities;
32 | QJsonArray m_attributes;
33 |
34 | [[nodiscard]] QJsonObject get_attribute(const QString &class_name,
35 | const QString &type = "",
36 | const QString &sub_type = "") const;
37 | };
38 |
39 | } // namespace Valeronoi::robot
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/src/robot/wifi_information.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "wifi_information.h"
19 |
20 | namespace Valeronoi::robot {
21 |
22 | class WifiInformationData : public QSharedData {
23 | public:
24 | WifiInformationData() {
25 | m_bssid = "00:00:00:00:00:00";
26 | m_ssid = "Unknown WiFi";
27 | m_signal = 0.0;
28 | }
29 |
30 | WifiInformationData(const WifiInformationData &other)
31 | : QSharedData(other),
32 | m_ssid(other.m_ssid),
33 | m_bssid(other.m_bssid),
34 | m_signal(other.m_signal) {}
35 |
36 | ~WifiInformationData() = default;
37 |
38 | QString m_ssid;
39 | QString m_bssid;
40 |
41 | double m_signal; // measurement
42 |
43 | // // Optionally this could be expanded
44 | // QString m_frequency;
45 | // QString m_ip;
46 | // QString m_ipv6;
47 | // double m_upspeed; // Measurement
48 | };
49 |
50 | WifiInformation::WifiInformation() : m_data(new WifiInformationData) {}
51 |
52 | WifiInformation::WifiInformation(const QJsonObject &jsonObj)
53 | : m_data(new WifiInformationData) {
54 | set_json(jsonObj);
55 | }
56 |
57 | WifiInformation::WifiInformation(const double signal)
58 | : m_data(new WifiInformationData) {
59 | set_signal(signal);
60 | }
61 |
62 | WifiInformation::WifiInformation(double signal, const QString &ssid,
63 | const QString &bssid)
64 | : m_data(new WifiInformationData) {
65 | set_signal(signal);
66 | set_ssid(ssid);
67 | set_bssid(bssid);
68 | }
69 |
70 | WifiInformation::WifiInformation(const WifiInformation &other)
71 | : m_data(other.m_data) {}
72 |
73 | WifiInformation &WifiInformation::operator=(const WifiInformation &rhs) {
74 | if (this != &rhs) m_data.operator=(rhs.m_data);
75 | return *this;
76 | }
77 |
78 | WifiInformation::~WifiInformation() { m_data.reset(); }
79 |
80 | void WifiInformation::set_ssid(const QString &ssid) { m_data->m_ssid = ssid; }
81 |
82 | void WifiInformation::set_bssid(const QString &bssid) {
83 | m_data->m_bssid = bssid;
84 | }
85 |
86 | void WifiInformation::set_signal(double signal) { m_data->m_signal = signal; }
87 |
88 | QString WifiInformation::ssid() const { return m_data->m_ssid; }
89 |
90 | QString WifiInformation::bssid() const { return m_data->m_bssid; }
91 |
92 | double WifiInformation::signal() const { return m_data->m_signal; }
93 |
94 | QJsonObject WifiInformation::get_json() const {
95 | QJsonObject retObj;
96 |
97 | retObj.insert("bssid", m_data->m_bssid);
98 | retObj.insert("ssid", m_data->m_ssid);
99 | retObj.insert("signal", m_data->m_signal);
100 |
101 | return retObj;
102 | }
103 |
104 | void WifiInformation::set_json(QJsonObject jsonObj) {
105 | if (jsonObj.contains("signal") && jsonObj["signal"].isDouble()) {
106 | m_data->m_signal = jsonObj["signal"].toDouble();
107 | }
108 |
109 | if (jsonObj.contains("bssid") && jsonObj["bssid"].isString()) {
110 | m_data->m_bssid = jsonObj["bssid"].toString();
111 | }
112 |
113 | if (jsonObj.contains("ssid") && jsonObj["ssid"].isString()) {
114 | m_data->m_ssid = jsonObj["ssid"].toString();
115 | }
116 | }
117 |
118 | bool WifiInformation::has_valid_signal() const {
119 | return (m_data->m_signal < -1);
120 | }
121 |
122 | } // namespace Valeronoi::robot
123 |
--------------------------------------------------------------------------------
/src/robot/wifi_information.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALETUDO_ROBOT_WIFI_INFORMATION_H
19 | #define VALETUDO_ROBOT_WIFI_INFORMATION_H
20 |
21 | #include
22 | #include
23 |
24 | namespace Valeronoi::robot {
25 |
26 | class WifiInformationData;
27 |
28 | class WifiInformation {
29 | public:
30 | WifiInformation();
31 | explicit WifiInformation(const QJsonObject &jsonObj);
32 | explicit WifiInformation(double signal);
33 | WifiInformation(double signal, const QString &ssid, const QString &bssid);
34 |
35 | WifiInformation(const WifiInformation &);
36 | WifiInformation &operator=(const WifiInformation &);
37 | ~WifiInformation();
38 |
39 | void set_ssid(const QString &ssid);
40 | void set_bssid(const QString &bssid);
41 | void set_signal(double signal);
42 |
43 | [[nodiscard]] QString ssid() const;
44 | [[nodiscard]] QString bssid() const;
45 | [[nodiscard]] double signal() const;
46 |
47 | [[nodiscard]] QJsonObject get_json() const;
48 | void set_json(QJsonObject jsonObj);
49 |
50 | [[nodiscard]] bool has_valid_signal() const;
51 |
52 | private:
53 | QSharedDataPointer m_data;
54 | };
55 |
56 | } // namespace Valeronoi::robot
57 | #endif // VALETUDO_ROBOT_WIFI_INFORMATION_H
58 |
--------------------------------------------------------------------------------
/src/state/measurements.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "measurements.h"
19 |
20 | namespace Valeronoi::state {
21 |
22 | void Measurements::set_map(const RobotMap &map) { m_map = ↦ }
23 |
24 | void Measurements::slot_add_measurement(double signal, int wifi_id) {
25 | if (m_map != nullptr && m_map->is_valid()) {
26 | if (auto robot_position = m_map->get_map().get_robot_position()) {
27 | add_measurement(robot_position.value().x, robot_position.value().y,
28 | signal, wifi_id);
29 | emit signal_measurements_updated();
30 | } else {
31 | qDebug() << "Could not find robot on map";
32 | }
33 | }
34 | }
35 |
36 | QJsonArray Measurements::get_json() const {
37 | QJsonArray arr;
38 | for (const auto &d : m_data) {
39 | auto obj = QJsonObject();
40 | obj.insert("x", d.x);
41 | obj.insert("y", d.y);
42 | obj.insert("wifi", d.wifi_id);
43 | auto data = QJsonArray();
44 | for (auto v : d.data) {
45 | data.append(v);
46 | }
47 | obj.insert("data", data);
48 | arr.append(obj);
49 | }
50 | return arr;
51 | }
52 |
53 | void Measurements::reset() {
54 | m_data.clear();
55 | emit signal_measurements_updated();
56 | }
57 |
58 | void Measurements::set_json(const QJsonArray &json) {
59 | m_data.clear();
60 | for (auto v : json) {
61 | const auto obj = v.toObject();
62 | int x = obj["x"].toInt();
63 | int y = obj["y"].toInt();
64 | int wifiId = unknown_wifi_id;
65 | if (obj.contains("wifi")) {
66 | wifiId = obj["wifi"].toInt(unknown_wifi_id);
67 | }
68 | for (auto m : obj["data"].toArray()) {
69 | add_measurement(x, y, m.toDouble(), wifiId);
70 | }
71 | }
72 | emit signal_measurements_updated();
73 | }
74 |
75 | void Measurements::add_measurement(int x, int y, double value, int wifi_id) {
76 | for (auto &d : m_data) {
77 | if (d.x == x && d.y == y && d.wifi_id == wifi_id) {
78 | d.data.push_back(value);
79 | double avg = 0;
80 | for (const auto &m : d.data) {
81 | avg += m;
82 | }
83 | d.average = avg / d.data.size();
84 | return;
85 | }
86 | }
87 | m_data.push_back(Measurement{x, y, wifi_id, {value}, value});
88 | }
89 |
90 | MeasurementStatistics Measurements::get_statistics() const {
91 | MeasurementStatistics ret{};
92 | ret.measurements = 0;
93 | ret.unique_places = m_data.size();
94 | ret.weakest = 0;
95 | ret.strongest = -1000;
96 | ret.unique_wifi_APs = 0;
97 | QVector temp_wifi_count;
98 | for (auto &m : m_data) {
99 | if (!temp_wifi_count.contains(m.wifi_id)) {
100 | temp_wifi_count.push_back(m.wifi_id);
101 | ret.unique_wifi_APs++;
102 | }
103 | for (auto &d : m.data) {
104 | ret.measurements++;
105 | ret.weakest = std::min(ret.weakest, d);
106 | ret.strongest = std::max(ret.strongest, d);
107 | }
108 | }
109 | return ret;
110 | }
111 |
112 | const RawMeasurements &Measurements::get_measurements() const { return m_data; }
113 |
114 | } // namespace Valeronoi::state
115 |
--------------------------------------------------------------------------------
/src/state/measurements.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_STATE_MEASUREMENTS_H
19 | #define VALERONOI_STATE_MEASUREMENTS_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #include "robot_map.h"
29 | #include "state.h"
30 |
31 | namespace Valeronoi::state {
32 |
33 | class Measurements : public QObject {
34 | Q_OBJECT
35 | public:
36 | void reset();
37 |
38 | void set_json(const QJsonArray &json);
39 |
40 | void set_map(const RobotMap &map);
41 |
42 | [[nodiscard]] const RawMeasurements &get_measurements() const;
43 |
44 | [[nodiscard]] QJsonArray get_json() const;
45 |
46 | [[nodiscard]] MeasurementStatistics get_statistics() const;
47 |
48 | int unknown_wifi_id = 0;
49 |
50 | signals:
51 | void signal_measurements_updated();
52 |
53 | public slots:
54 | void slot_add_measurement(double signal, int wifi_id);
55 |
56 | private:
57 | void add_measurement(int x, int y, double value, int wifi_id);
58 |
59 | const RobotMap *m_map{nullptr};
60 |
61 | std::vector m_data;
62 | };
63 |
64 | } // namespace Valeronoi::state
65 |
66 | #endif
67 |
--------------------------------------------------------------------------------
/src/state/robot_map.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "robot_map.h"
19 |
20 | #include
21 |
22 | #ifndef M_PI
23 | #define M_PI 3.14159265358979323846
24 | #endif
25 |
26 | namespace Valeronoi::state {
27 | RobotMap::RobotMap(QObject *parent) : QObject(parent) { reset(); }
28 |
29 | void RobotMap::update_map_json(const QString &json) {
30 | m_error = "";
31 | m_valid = false;
32 | if (json == "null") {
33 | // Edge case, because QJsonDocument::fromJson also returns null if it
34 | // detects a parsing error
35 | m_error = tr("No map data");
36 | emit signal_map_updated();
37 | return;
38 | }
39 |
40 | QJsonParseError error;
41 | auto json_document = QJsonDocument::fromJson(json.toUtf8(), &error);
42 | if (json_document.isNull()) {
43 | m_error = error.errorString();
44 | emit signal_map_updated();
45 | return;
46 | }
47 | if (json_document.isEmpty()) {
48 | m_error = tr("No map data");
49 | emit signal_map_updated();
50 | return;
51 | }
52 | update_map_json(json_document.object());
53 | }
54 |
55 | void RobotMap::update_map_json(const QJsonObject &json_object) {
56 | if (json_object["__class"].toString() != "ValetudoMap") {
57 | m_error = tr("Did not receive ValetudoMap");
58 | emit signal_map_updated();
59 | return;
60 | }
61 |
62 | m_map_version = json_object["metaData"].toObject()["version"].toInt();
63 | if (m_map_version < 1 || m_map_version > 2) {
64 | m_error = tr("Unknown map version");
65 | emit signal_map_updated();
66 | return;
67 | }
68 |
69 | m_map_json = json_object;
70 | generate_map();
71 | m_valid = true;
72 | emit signal_map_updated();
73 | }
74 |
75 | template
76 | static void map_pixels(const QJsonArray &pixels, T &blocks, int pixel_size,
77 | int *min_x, int *max_x, int *min_y, int *max_y) {
78 | blocks.reserve(pixels.size() / 2);
79 | for (qsizetype i = 0; i + 1 < pixels.size(); i += 2) {
80 | int block_x = pixels[i].toInt() * pixel_size;
81 | int block_y = pixels[i + 1].toInt() * pixel_size;
82 | *min_x = std::min(*min_x, block_x);
83 | *max_x = std::max(*max_x, block_x + pixel_size);
84 | *min_y = std::min(*min_y, block_y);
85 | *max_y = std::max(*max_y, block_y + pixel_size);
86 | blocks.push_back({block_x, block_y});
87 | }
88 | }
89 |
90 | template
91 | static void map_pixels(const std::unordered_set &pixels, T &blocks,
92 | int pixel_size, int *min_x, int *max_x, int *min_y,
93 | int *max_y) {
94 | blocks.reserve(pixels.size() / 2);
95 | for (const auto &block : pixels) {
96 | int block_x = block.x * pixel_size;
97 | int block_y = block.y * pixel_size;
98 | *min_x = std::min(*min_x, block_x);
99 | *max_x = std::max(*max_x, block_x + pixel_size);
100 | *min_y = std::min(*min_y, block_y);
101 | *max_y = std::max(*max_y, block_y + pixel_size);
102 | blocks.push_back({block_x, block_y});
103 | }
104 | }
105 |
106 | template
107 | static void move_pixels(T &blocks, int move_x, int move_y) {
108 | for (auto &block : blocks) {
109 | block.x += move_x;
110 | block.y += move_y;
111 | }
112 | }
113 |
114 | void RobotMap::generate_map() {
115 | m_map = Map();
116 | m_map.size_x = m_map_json["size"].toObject()["x"].toInt();
117 | m_map.size_y = m_map_json["size"].toObject()["y"].toInt();
118 | m_map.pixel_size = m_map_json["pixelSize"].toInt();
119 | int min_x{m_map.size_x}, max_x{0}, min_y{m_map.size_y}, max_y{0};
120 |
121 | // Because we merge layers together, pixels/blocks may occur multiple times in
122 | // a Layer. As layers are already a performance problem, we have to remove
123 | // duplicates by using an unordered_set.
124 | std::unordered_map> floor_pixels;
125 | for (const auto &&layer : m_map_json["layers"].toArray()) {
126 | const auto &layer_obj = layer.toObject();
127 | auto layer_type = layer_obj["type"].toString().toStdString();
128 | if (layer_type == "segment") {
129 | // Pretend segments are floor as well, because future Valetudo Versions
130 | // will not have "floor". Dreame Robots don't have a floor layer at all.
131 | layer_type = "floor";
132 | }
133 | if (layer_type == "floor" || layer_type == "wall") {
134 | if (m_map_version == 1) {
135 | const auto &pixels = layer_obj["pixels"].toArray();
136 | if ((pixels.size() % 2) != 0 || pixels.size() < 2) {
137 | qDebug().nospace()
138 | << "Invalid layer, has " << pixels.size() << " points";
139 | continue;
140 | }
141 |
142 | floor_pixels[layer_type].reserve(pixels.size() / 2);
143 | for (qsizetype i = 0; i + 1 < pixels.size(); i += 2) {
144 | const int block_x = pixels[i].toInt();
145 | const int block_y = pixels[i + 1].toInt();
146 | floor_pixels[layer_type].insert({block_x, block_y});
147 | }
148 | } else if (m_map_version == 2) {
149 | const auto &compressed_pixels = layer_obj["compressedPixels"].toArray();
150 | if ((compressed_pixels.size() % 3) != 0 ||
151 | compressed_pixels.size() < 3) {
152 | qDebug().nospace()
153 | << "Invalid layer, has " << compressed_pixels.size() << " points";
154 | continue;
155 | }
156 |
157 | for (qsizetype i = 0; i + 1 < compressed_pixels.size(); i += 3) {
158 | const int block_x = compressed_pixels[i].toInt();
159 | const int block_y = compressed_pixels[i + 1].toInt();
160 | const int block_count = compressed_pixels[i + 2].toInt();
161 | for (qsizetype j = 0; j < block_count; j++) {
162 | const auto pixel_x = static_cast(block_x + j);
163 | floor_pixels[layer_type].insert({pixel_x, block_y});
164 | }
165 | }
166 | }
167 | }
168 | }
169 | for (const auto &layer : floor_pixels) {
170 | map_pixels(layer.second, m_map.layers[layer.first].blocks, m_map.pixel_size,
171 | &min_x, &max_x, &min_y, &max_y);
172 | }
173 |
174 | for (const auto &&entity : m_map_json["entities"].toArray()) {
175 | const auto &entity_obj = entity.toObject();
176 | const auto entity_class = entity_obj["__class"].toString();
177 | const auto entity_type = entity_obj["type"].toString();
178 | const auto entity_metadata = entity_obj["metaData"].toObject();
179 | const auto &points = entity_obj["points"].toArray();
180 | if (entity_class == "PointMapEntity" && points.size() != 2) {
181 | qDebug().nospace() << "Found PointMapEntity with not 2 points but "
182 | << points.size() << ", ignoring";
183 | continue;
184 | }
185 | if (entity_type.endsWith("_position") && entity_class != "PointMapEntity") {
186 | qDebug() << entity_type << "entity must be a PointMapEntity, but was"
187 | << entity_class;
188 | continue;
189 | }
190 | const auto entity_type_str = entity_type.toStdString();
191 | Entity map_entity;
192 | map_entity.type = entity_type_str;
193 | map_entity.cls = entity_class.toStdString();
194 | map_pixels(points, map_entity.points, 1, &min_x, &max_x, &min_y, &max_y);
195 | map_entity.angle =
196 | (entity_metadata["angle"].toDouble() - 90.0) * M_PI / 180.0;
197 |
198 | if (map_entity.type == "robot_position") {
199 | // Insert robot position last to ensure the robot is drawn last
200 | m_map.entities.push_back(map_entity);
201 | } else {
202 | m_map.entities.insert(m_map.entities.begin(), map_entity);
203 | }
204 | }
205 |
206 | for (auto &layer : m_map.layers) {
207 | move_pixels(layer.second.blocks, -min_x, -min_y);
208 | }
209 |
210 | for (auto &layer : m_map.entities) {
211 | move_pixels(layer.points, -min_x, -min_y);
212 | }
213 | m_map.size_x = max_x - min_x;
214 | m_map.size_y = max_y - min_y;
215 | m_map.crop_x = min_x;
216 | m_map.crop_y = min_y;
217 | qDebug() << "Generated map with size" << m_map.size_x << "x" << m_map.size_y
218 | << "- cropped" << m_map.crop_x << "x" << m_map.crop_y;
219 | }
220 |
221 | bool RobotMap::is_valid() const { return m_valid; }
222 |
223 | QString RobotMap::error_msg() const { return m_error; }
224 |
225 | const Map &RobotMap::get_map() const { return m_map; }
226 |
227 | const QJsonObject &RobotMap::get_map_json() const { return m_map_json; }
228 |
229 | void RobotMap::reset() {
230 | m_valid = false;
231 | m_error = "No map data";
232 | emit signal_map_updated();
233 | }
234 |
235 | } // namespace Valeronoi::state
236 |
--------------------------------------------------------------------------------
/src/state/robot_map.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_STATE_ROBOT_MAP_H
19 | #define VALERONOI_STATE_ROBOT_MAP_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include "state.h"
28 |
29 | namespace Valeronoi::state {
30 |
31 | class RobotMap : public QObject {
32 | Q_OBJECT
33 | public:
34 | explicit RobotMap(QObject *parent = nullptr);
35 |
36 | void update_map_json(const QString &json);
37 |
38 | void update_map_json(const QJsonObject &json);
39 |
40 | void reset();
41 |
42 | [[nodiscard]] bool is_valid() const;
43 |
44 | [[nodiscard]] QString error_msg() const;
45 |
46 | [[nodiscard]] const Map &get_map() const;
47 |
48 | [[nodiscard]] const QJsonObject &get_map_json() const;
49 |
50 | signals:
51 | void signal_map_updated();
52 |
53 | private:
54 | void generate_map();
55 |
56 | QJsonObject m_map_json{};
57 | int m_map_version{0};
58 | bool m_valid{false};
59 | QString m_error;
60 | Map m_map;
61 | };
62 | } // namespace Valeronoi::state
63 |
64 | #endif
65 |
--------------------------------------------------------------------------------
/src/state/state.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "state.h"
19 |
20 | #include
21 |
22 | namespace Valeronoi::state {
23 |
24 | std::optional Map::get_robot_position() const {
25 | auto res = std::find_if(entities.begin(), entities.end(), [=](const auto &e) {
26 | return e.type == "robot_position";
27 | });
28 | if (res == entities.end()) {
29 | return std::nullopt;
30 | }
31 | return {res->points[0]};
32 | }
33 |
34 | } // namespace Valeronoi::state
35 |
--------------------------------------------------------------------------------
/src/state/state.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_STATE_STATE_H
19 | #define VALERONOI_STATE_STATE_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | namespace Valeronoi::state {
32 |
33 | struct Point {
34 | int x, y;
35 | };
36 |
37 | struct Block {
38 | int x, y;
39 | };
40 |
41 | inline bool operator==(const Block &lhs, const Block &rhs) {
42 | return lhs.x == rhs.x && lhs.y == rhs.y;
43 | }
44 |
45 | inline bool operator<(const Block &lhs, const Block &rhs) {
46 | return (lhs.x + lhs.y) < (rhs.x + rhs.y);
47 | }
48 |
49 | struct Entity {
50 | std::string type, cls;
51 | double angle;
52 | std::vector points;
53 | };
54 |
55 | struct Layer {
56 | std::vector blocks;
57 | };
58 |
59 | struct Map {
60 | int pixel_size;
61 | int size_x, size_y;
62 | int crop_x, crop_y;
63 | std::unordered_map layers;
64 | std::vector entities;
65 |
66 | std::optional get_robot_position() const;
67 | };
68 |
69 | struct Measurement {
70 | int x, y;
71 | int wifi_id;
72 | std::vector data;
73 | double average;
74 | };
75 |
76 | typedef std::vector RawMeasurements;
77 |
78 | struct MeasurementStatistics {
79 | int measurements, unique_places, unique_wifi_APs;
80 | double strongest, weakest;
81 | };
82 |
83 | enum class DISPLAY_MODE {
84 | Voronoi = 0,
85 | DataPoints = 1,
86 | None = 2
87 | }; // Keep in sync with valeronoi.ui
88 |
89 | struct DataSegment {
90 | int x{0}, y{0};
91 | double value{0.0};
92 | QPolygon polygon;
93 | QColor color;
94 | };
95 |
96 | typedef QList DataSegments;
97 |
98 | } // namespace Valeronoi::state
99 |
100 | namespace std {
101 | template <>
102 | struct hash {
103 | std::size_t operator()(Valeronoi::state::Block const &s) const noexcept {
104 | std::size_t h1 = std::hash{}(s.x);
105 | std::size_t h2 = std::hash{}(s.y);
106 | return h1 ^ (h2 << 1);
107 | }
108 | };
109 | } // namespace std
110 |
111 | #ifndef Q_DECLARE_METATYPE
112 | // To make cppcheck happy
113 | #define Q_DECLARE_METATYPE(TYPE) // TYPE
114 | #endif
115 | Q_DECLARE_METATYPE(Valeronoi::state::DataSegments)
116 |
117 | #endif
118 |
--------------------------------------------------------------------------------
/src/state/wifi_collection.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include "wifi_collection.h"
20 |
21 | #include "qjsonarray.h"
22 |
23 | namespace Valeronoi::state {
24 |
25 | wifi_collection::wifi_collection() { clear(); }
26 |
27 | void wifi_collection::clear() { m_known_wifis.clear(); }
28 |
29 | int wifi_collection::get_or_create_wifi_id(
30 | const Valeronoi::robot::WifiInformation& wifi_info) {
31 | int nRet = get_wifi_id(wifi_info.bssid());
32 |
33 | if (nRet < 0) {
34 | nRet = add_wifi(wifi_info);
35 | }
36 |
37 | return nRet;
38 | }
39 |
40 | int wifi_collection::add_wifi(
41 | const Valeronoi::robot::WifiInformation& wifi_info) {
42 | m_known_wifis.append(wifi_info);
43 |
44 | emit signal_wifi_list_updated();
45 | emit signal_new_wifi_added(wifi_info);
46 |
47 | return m_known_wifis.size() - 1;
48 | }
49 |
50 | QVector wifi_collection::get_known_wifis()
51 | const {
52 | return m_known_wifis;
53 | }
54 |
55 | QJsonArray wifi_collection::get_json() const {
56 | QJsonArray ret;
57 |
58 | for (const auto& m_known_wifi : m_known_wifis) {
59 | ret.append(m_known_wifi.get_json());
60 | }
61 |
62 | return ret;
63 | }
64 |
65 | void wifi_collection::set_json(const QJsonArray& json) {
66 | clear();
67 |
68 | for (const auto& wifi_access_point_value : json) {
69 | if (!wifi_access_point_value.isObject()) {
70 | // Wrong format.
71 | return;
72 | }
73 | QJsonObject wifi_access_point = wifi_access_point_value.toObject();
74 | m_known_wifis.append(Valeronoi::robot::WifiInformation(wifi_access_point));
75 | }
76 |
77 | emit signal_wifi_list_updated();
78 | }
79 |
80 | int wifi_collection::get_wifi_id(const QString& bssid) const {
81 | for (int index = 0; m_known_wifis.size() > index; ++index) {
82 | if (m_known_wifis.at(index).bssid() == bssid) {
83 | return index;
84 | }
85 | }
86 |
87 | return -1;
88 | }
89 |
90 | } // namespace Valeronoi::state
91 |
--------------------------------------------------------------------------------
/src/state/wifi_collection.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_STATE_WIFI_COLLECTION_H
19 | #define VALERONOI_STATE_WIFI_COLLECTION_H
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | #include "../robot/wifi_information.h"
26 |
27 | namespace Valeronoi::state {
28 |
29 | class wifi_collection : public QObject {
30 | Q_OBJECT
31 | public:
32 | wifi_collection();
33 |
34 | void clear();
35 |
36 | int get_or_create_wifi_id(const Valeronoi::robot::WifiInformation& wifi_info);
37 |
38 | [[nodiscard]] int get_wifi_id(const QString& bssid) const;
39 |
40 | int add_wifi(const Valeronoi::robot::WifiInformation& wifi_info);
41 |
42 | [[nodiscard]] QVector get_known_wifis()
43 | const;
44 |
45 | [[nodiscard]] QJsonArray get_json() const;
46 |
47 | void set_json(const QJsonArray& json);
48 |
49 | signals:
50 | void signal_wifi_list_updated();
51 |
52 | void signal_new_wifi_added(Valeronoi::robot::WifiInformation wifi_info);
53 |
54 | private:
55 | QVector m_known_wifis;
56 | };
57 |
58 | } // namespace Valeronoi::state
59 |
60 | #endif // VALERONOI_STATE_WIFI_COLLECTION_H
61 |
--------------------------------------------------------------------------------
/src/util/colormap.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_UTIL_COLORMAP_H
19 | #define VALERONOI_UTIL_COLORMAP_H
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | namespace Valeronoi::util {
27 | template
28 | class ColorMap {
29 | public:
30 | ColorMap(const char *name, std::vector> colors)
31 | : colormap_name{name}, colormap_colors{std::move(colors)} {
32 | if (colormap_colors.size() == 0) {
33 | throw std::runtime_error("Can not initialize ColorMap without colors");
34 | }
35 | };
36 |
37 | [[nodiscard]] std::string name() const { return colormap_name; };
38 |
39 | [[nodiscard]] std::array get_color(T f) const {
40 | if (f <= 0) return colormap_colors[0];
41 | if (f >= 1) return colormap_colors[colormap_colors.size() - 1];
42 | double place = (colormap_colors.size() - 1) * f;
43 | double int_part, fract_part;
44 | fract_part = std::modf(place, &int_part);
45 | std::size_t index = int_part;
46 | if (index == colormap_colors.size() - 1) {
47 | // VERY close to end
48 | return colormap_colors[colormap_colors.size() - 1];
49 | }
50 | assert((index < colormap_colors.size() - 1));
51 |
52 | std::array ret{};
53 | for (std::size_t i = 0; i < components; i++) {
54 | ret[i] = (1.0 - fract_part) * colormap_colors[index][i];
55 | }
56 |
57 | for (std::size_t i = 0; i < components; i++) {
58 | ret[i] += fract_part * colormap_colors[index + 1][i];
59 | }
60 |
61 | return ret;
62 | }
63 |
64 | private:
65 | std::string colormap_name;
66 | std::vector> colormap_colors;
67 | };
68 |
69 | typedef ColorMap RGBColorMap;
70 | typedef std::array RGBColorMapColors;
71 |
72 | } // namespace Valeronoi::util
73 |
74 | #endif
75 |
--------------------------------------------------------------------------------
/src/util/compat.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_UTIL_COMPAT_H
19 | #define VALERONOI_UTIL_COMPAT_H
20 |
21 | #include
22 | #include
23 |
24 | #if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
25 | #define CHECKBOX_SIGNAL_CHANGED QCheckBox::stateChanged
26 | #else
27 | #define CHECKBOX_SIGNAL_CHANGED QCheckBox::checkStateChanged
28 | #endif
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/util/log_helper.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include "log_helper.h"
20 |
21 | #include
22 |
23 | namespace Valeronoi::util {
24 |
25 | LogHelper &LogHelper::instance() {
26 | static LogHelper _instance;
27 | return _instance;
28 | }
29 |
30 | void LogHelper::log(const QString &msg) {
31 | if (!m_log_dialog) {
32 | m_buffer.append(msg);
33 | } else {
34 | m_log_dialog->log_message(msg);
35 | }
36 | }
37 |
38 | void LogHelper::set_log_dialog(Valeronoi::gui::dialog::LogDialog *log_dialog) {
39 | m_log_dialog = log_dialog;
40 | m_log_dialog->log_message(m_buffer);
41 | m_buffer.clear();
42 | }
43 |
44 | void log_handler(QtMsgType type, const QMessageLogContext &context,
45 | const QString &msg) {
46 | (void)context;
47 | auto &helper = LogHelper::instance();
48 | QString level;
49 | switch (type) {
50 | case QtDebugMsg:
51 | level = "DEBUG";
52 | break;
53 | case QtWarningMsg:
54 | level = "WARN ";
55 | break;
56 | case QtCriticalMsg:
57 | level = "CRIT ";
58 | break;
59 | case QtFatalMsg:
60 | level = "FATAL";
61 | break;
62 | case QtInfoMsg:
63 | level = "INFO ";
64 | break;
65 | }
66 | const auto time = QDateTime::currentDateTime();
67 | helper.log("[ " + level + " ] " + time.toString("yyyy-MM-dd hh:mm:ss.zzz") +
68 | " " + msg);
69 | }
70 |
71 | } // namespace Valeronoi::util
72 |
--------------------------------------------------------------------------------
/src/util/log_helper.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #ifndef VALERONOI_UTIL_LOG_HELPER_H
19 | #define VALERONOI_UTIL_LOG_HELPER_H
20 |
21 | #include
22 | #include
23 |
24 | #include "../gui/dialog/log.h"
25 |
26 | namespace Valeronoi::util {
27 |
28 | class LogHelper {
29 | public:
30 | static LogHelper &instance();
31 |
32 | LogHelper(const LogHelper &) = delete;
33 |
34 | LogHelper &operator=(const LogHelper &) = delete;
35 |
36 | void set_log_dialog(Valeronoi::gui::dialog::LogDialog *log_dialog);
37 |
38 | void log(const QString &msg);
39 |
40 | private:
41 | LogHelper() = default;
42 |
43 | QString m_buffer;
44 | Valeronoi::gui::dialog::LogDialog *m_log_dialog{nullptr};
45 | };
46 |
47 | void log_handler(QtMsgType type, const QMessageLogContext &context,
48 | const QString &msg);
49 |
50 | } // namespace Valeronoi::util
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/src/util/segment_generator.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Valeronoi is an app for generating WiFi signal strength maps
3 | * Copyright (C) 2021-2024 Christian Friedrich Coors
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 | #include "segment_generator.h"
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include
27 |
28 | typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
29 | typedef CGAL::Delaunay_triangulation_2 DT;
30 | typedef CGAL::Delaunay_triangulation_adaptation_traits_2