The PDF Toolkit is starting to feel like a real application now.
After finishing the main PDF operations and the interactive CLI, I focused this time on adding text extraction and improving the overall reliability of the program.
I added a new PDF → Text operation using PyMuPDF.
The tool goes through the pages of a PDF, extracts the text and saves everything into a .txt file.
This makes it possible to quickly get the text from a PDF without manually copying it page by page.
The extracted text keeps the content from all pages in the document.
I also spent some time making the CLI more reliable.
The program now handles common problems such as:
Instead of crashing immediately, the CLI can display an error and return to the main menu.
The CLI now gives clearer feedback when an operation finishes.
For example:
✓ PDF merged successfully!
If an operation fails, the user gets an error message instead of being left with a Python traceback.
This makes the tool much easier to use, especially for someone who doesn’t know how the code works internally.
I also added basic command-line options to make the program easier to use outside of the interactive menu.
The application now supports:
--help
for displaying information about the available commands and options, and:
--version
for displaying the current version of PDF Toolkit.
These are small additions, but they make the project feel much more like a proper command-line application.
At this point, PDF Toolkit supports:
--help--versionThe project is now much more complete than when I started.
I’ve been testing the different operations both individually and through the CLI.
The main goal is to make sure that the normal workflow works correctly while also handling common user mistakes without crashing the application.
There are still things I want to test more thoroughly before calling the project finished, especially when packaging it for other computers.
The core functionality is now basically finished.
The next step is no longer about adding lots of new features. I want to focus on actually shipping the project.
The next stage will be:
.exe
v1.0.0 🚀
The goal is to have a version that someone can download and use without needing to manually set up the Python environment.
The first usable version of the PDF Toolkit CLI is now complete.
I created cli.py and connected all of the PDF operations that were already implemented to a single interactive interface.
The CLI is built using Questionary for the terminal menu and Tkinter file dialogs for selecting input and output files.
The CLI currently supports:
Each operation can now be selected directly from the terminal.
Instead of requiring users to manually type file paths, the CLI uses Tkinter file dialogs to select files and folders.
For example, when merging PDFs, the user can:
The same approach is used for the other operations where appropriate.
The CLI asks the user for the page number and then allows them to choose where the generated image should be saved.
For splitting PDFs, the user can select:
This keeps the generated files organized.
The CLI also supports the page selection syntax implemented in the extraction function.
For example:
1-5
or:
1,3,5-8
The selected pages are then saved into a new PDF.
The core PDF operations are now implemented and accessible through the CLI.
The project has moved from individual PDF functions to an actual usable command-line application.
The next step is to improve the CLI experience and make the tool more reliable.
Possible improvements include:
I’ve started building PDF Toolkit, a small Python command-line utility for working with PDF files.
The goal is to keep it simple and modular, while gradually adding useful PDF operations.
PDF-Toolkit/
├── main.py
├── requirements.txt
├── operations/
│ ├── __init__.py
│ ├── merge.py
│ ├── convert.py
│ ├── split.py
│ └── extract.py
└── tests/
├── __init__.py
└── test_merge.py
The PDF operations are separated into individual modules instead of putting everything into one file.
Added support for combining multiple PDF files into a single PDF.
The merge operation uses PyMuPDF and accepts multiple input files.
Added support for converting a specific PDF page into an image.
Current options include:
Added support for splitting a PDF into individual pages.
For example, a multi-page PDF can be split into separate files:
page_1.pdf
page_2.pdf
page_3.pdf
...
Added support for extracting selected pages into a new PDF.
Pages can be specified individually or as ranges.
Example:
2,5,8-10
This creates a new PDF containing pages 2, 5, 8, 9 and 10.
The next step is to connect all the existing operations through a simple CLI interface.
The user will be able to start PDF Toolkit and select an operation from a menu:
PDF Toolkit
1. Merge PDFs
2. PDF → Image
3. Split PDF
4. Extract Pages
5. Exit
This will make the current features easier to use without having to call the Python functions manually.
After the CLI is working, I plan to continue expanding the toolkit with more PDF operations.
Planned features:
For now, the focus is on getting the existing features working properly and making them easy to use through the CLI.
Transitioned RoomOps Zero from a software dashboard into a fully physical retro-tech robot assistant. The physical chassis has been built—featuring an acrylic robot enclosure complete with an integrated LED Matrix display that serves as an expressive face/visual telemetry hub.
On the software side, fully deployed the core security engine in main.py. The backend now supports dynamic system arming/disarming, security PIN verification, automated motion monitoring loops, and immediate smart home alert triggers (escalating room volume, dispatching notifications, and turning Tapo L900 smart light strips red upon motion detection).
Chassis & Enclosure)
main.py)
armed = False) to track real-time security modes across all REST endpoints.POST /api/verify-pin utilizing Pydantic validation (PinModel) against environment parameters (SECURITY_PIN)./api/arm & /api/disarm) for rapid arming/disarming from web controls and action blocks.services/camera.py)
/api/camera/check-motion endpoint to continuously poll motion sensors when the system is armed.utils.notifier.utils.volume.tapo_control.DeviceFactory by powering on the Tapo L900 light strip and setting its colour directly to Red./static/last_motion.jpg for active monitoring logging.Security State Management
GET / POST /api/arm → Sets system status to armed: true.GET / POST /api/disarm → Sets system status to armed: false.GET /api/status → Returns current system state ({"system_armed": armed}).Security PIN Verification
POST /api/verify-pin
{
"pin": "1234"
}
{
"status": "success",
"correct": true,
"system_armed": false
}
Motion Detection Polling Endpoint
GET /api/camera/check-motion
{
"motion": true,
"system_armed": true,
"timestamp": "2026-08-26T15:56:00",
"image_url": "/static/last_motion.jpg"
}
Elevated the RoomOps Zero ecosystem into a 24/7 ambient TV control station by integrating a real-time RSS news telemetry service.
This update includes:
Files: services/news.py · main.py
feedparser to extract and process localized Google News RSS feeds.GET /api/news/{city}
File: templates/index.html
fade-in and fade-out effects.Elevated the RoomOps Zero ecosystem by transitioning from a headless microservice layer to an interactive web dashboard. Resolved Starlette/FastAPI ASGI rendering exceptions, eliminated recursive 404 image load loops, and consolidated CSS styling alongside asynchronous JavaScript directly into the template architecture. The dashboard now renders real-time telemetry, handles local clock synchronization, and triggers remote hardware states directly through non-blocking API requests.
main.py)
TypeError: unhashable type: 'dict' caused by Starlette context signature updates in newer FastAPI releases.Jinja2Templates rendering by explicitly passing keyword parameters (request=request).templates/index.html seamlessly alongside existing JSON routes.templates/index.html)
<style> and <script> blocks to bypass static pathing overhead and network latency.window.location.origin to allow dynamic REST execution across varying local IPs and ports.turn_on / turn_off) to POST /api/tapo/control payloads.GET /api/weather/{city}) with fallback status handlers.onerror fallback loop by decoupling broken image streams and nullifying error handlers.GET /
index.html)fetch('${API_BASE_URL}/api/weather/kavala')
POST /api/tapo/control with {"device_name": "l900", "action": "turn_on"}
Date: August 23, 2026
Project: RoomOps Zero
Status: In Progress (Backend Microservice Layer)
Implemented the foundational REST API layer for RoomOps Zero using FastAPI to handle local hardware control and environmental telemetry. Integrated Tapo smart devices (L900 Light Strip & L535 Smart Bulb) using an asynchronous client library (tapo), structured via the Factory Design Pattern for modularity. Added an asynchronous weather integration module to feed current climate data directly to the central dashboard.
main.py)
0.0.0.0:8080 via Uvicorn.TapoBaseModel).GET) and smart device state management (POST).tapo_control.py)
L900, L535) leveraging ApiClient from the tapo library..env file using python-dotenv.L535 to avoid redundant object instantiation.DeviceFactory class to standardize turn_on and turn_off operations across varying hardware models based on incoming payloads.weather.py)
python_weather using metric units ($^\circ\text{C}$).async utility (get_temperature) to prevent blocking the primary event loop during HTTP requests.GET /api/weather/{city}
city (path parameter, string)POST /api/tapo/control
Content-Type: application/json
{
"device_name": "l900",
"action": "turn_on"
}
This devlog details the core backend infrastructure, API endpoints, and real-time mapping interface developed for the AERIS-Rover (Autonomous Eco-Robotic Intelligence System) project. The system is designed to coordinate outdoor AGVs (Autonomous Ground Vehicles) for environmental data collection and automated Return-to-Base (RTB) operations[cite: 1].
server.py)
Built using Python (Flask), the backend acts as the central command node running on a Raspberry Pi 5 (8GB)[cite: 1, 2]. It handles multi-robot telemetry, dynamic mission routing, and real-time client requests.
/api/robot/location (POST): Receives real-time latitude, longitude updates from rovers and calculates operational distances[cite: 2]./api/robot/status (POST): Tracks live health metrics including battery percentages, internet connectivity, error flags, and active mission states[cite: 2]./api/robot/missions/set & /api/robot/missions (GET/POST): Manages mission generation, payload parsing, and waypoint distribution[cite: 2]./api/robot/request (GET/POST): Handles asynchronous command queues for individual robot agents[cite: 2].index.html)
The frontend dashboard provides visualization of the robot fleet operating in outdoor environments[cite: 1].
Today I expanded AutoStudy AI’s study pipeline by introducing AI-generated flashcards with an interactive flip-card interface, alongside a cleaner and more polished user experience.
Qwen2.5:3b (Ollama) to automatically parse PDF text into 5–8 study flashcards (Questions & Answers).Card X of Y), and sleek loading animations during document processing.AutoStudy AI is evolving from a basic text extractor into a true, active-recall study tool. By combining local AI intelligence with interactive flashcards, users can now test their knowledge directly from their study materials while maintaining 100% data privacy and offline capability.
Qwen2.5:3b for local structured JSON extraction)Implement custom study tool selection on the homepage (allowing users to choose between summaries, flashcards, or AI assistants per upload) and build a history sidebar for quick access to past documents.
Second milestone achieved: active recall study workflows are now fully operational offline. 🚀
Today I integrated Ollama with Qwen2.5:3b to generate AI-powered summaries directly from extracted PDF text.
AutoStudy AI now has local intelligence. The model runs locally on GPU (~4GB VRAM), allowing fast iteration and proving that small open-source LLMs handle Greek/English PDFs effectively for flashcards, quizzes, and concept extraction.
Add CSS styling for a polished UI (dark mode, card layouts, mobile responsiveness, and loading animations).
Today I implemented the core document pipeline for AutoStudy AI.
This is the first end-to-end workflow of the project. AutoStudy AI can now take a document and convert it into machine-readable text, which will be the foundation for:
Integrate Ollama + Qwen3 to generate local AI summaries directly from the extracted text.
First milestone achieved: documents can now enter the AI pipeline completely offline. 🚀
This update also focuses on improving the project’s reliability and development workflow.
Added 20 Pytest test cases covering the core functionality of the system, helping verify that critical components behave correctly and reducing the risk of regressions.
Configured GitHub Actions to automatically execute the entire test suite after every commit and pull request, ensuring new changes don’t break existing functionality.
Automated testing and Continuous Integration (CI) make the project more robust, maintainable, and production-ready. Every code change is now automatically validated before it becomes part of the project, providing faster feedback during development and increasing confidence in future updates.
Docker support for the Edge-AI Home Monitoring System is now fully working end-to-end.
start.bat
start.sh
No more manually running docker compose, checking dependencies, or following multi-step instructions. Just run the script for your OS and the entire stack comes up ready to use.
This closes the loop on the Docker migration from a few devlogs ago. Before, Docker removed the Python/venv/dependency headaches but still required knowing the right compose commands. Now the onboarding experience is genuinely “clone → run one script → done,” with the HTML first-run page handling the last bit of manual setup that used to require touching config files by hand.
The Edge-AI Home Monitoring System has just received its most significant infrastructure overhaul yet!
We have completely re-engineered the deployment workflow. Instead of dealing with manual environment configurations, matching Python versions, and tracking down dependency conflicts, the entire ecosystem can now be spun up instantly with a single command.
By migrating the platform to a fully containerized backend, we’ve moved away from fragile local setups closer to a production-grade deployment.
devices_config.json, automation rules, and local database models are securely mapped via Docker volumes, meaning they persist perfectly across container restarts and updates.The difference in onboarding friction is night and day. Look at how the installation footprint has shrunk:
Old Manual Setup New Docker Workflow ❌ Install Python manually & match versions 📦 Pre-configured runtime environment ❌ Create virtual environments (venv)
📦 Isolated container filesystems
❌ Debug pip dependency conflicts
📦 One-time automated image build
❌ Manually set environment variables
📦 Declarative configuration via Compose
❌ Run background scripts step-by-step
📦 Single-command multi-service launch
Now, launching your privacy-first smart home hub requires nothing more than standard container tools:
# Clone the repository
git clone https://github.com/travletothefurureprogramming/Edge-AI-Home-Monitoring-System
# Navigate to the project root
cd Edge-AI-Home-Monitoring-System
# Spin up the entire system in detached mode
docker compose up -d
Enchanse CLI app using questionary and start making a clean README with clear explanation on how to use it
Fix some bugs and create a clean repository with a good README and the github release.