# PyFlowerCare
A Python library for communicating with FlowerCare (Xiaomi MiFlora) Bluetooth plant sensors.
## Features
- **Device Discovery**: Scan and discover FlowerCare devices via Bluetooth Low Energy
- **Real-time Sensor Data**: Read temperature, brightness, soil moisture, and conductivity
- **Historical Data**: Access stored historical measurements from the device
- **Device Management**: Connect, disconnect, and manage multiple devices
- **Async Support**: Full asyncio support for non-blocking operations
- **Error Handling**: Comprehensive exception handling with meaningful error messages
## Installation
```bash
pip install pyflowercare
```
## Requirements
- Python 3.9+
- Bluetooth Low Energy support
- Linux/macOS/Windows with Bluetooth adapter
## Quick Start
### Basic Usage
```python
import asyncio
from flowercare import FlowerCareScanner
async def main():
scanner = FlowerCareScanner()
# Scan for devices
devices = await scanner.scan_for_devices(timeout=10.0)
if devices:
device = devices[0]
# Connect and read data
async with device:
sensor_data = await device.read_sensor_data()
print(f"Temperature: {sensor_data.temperature}°C")
print(f"Brightness: {sensor_data.brightness} lux")
print(f"Moisture: {sensor_data.moisture}%")
print(f"Conductivity: {sensor_data.conductivity} µS/cm")
asyncio.run(main())
```
### Device Information
```python
async with device:
info = await device.get_device_info()
print(f"Device: {info.name}")
print(f"MAC: {info.mac_address}")
print(f"Battery: {info.battery_level}%")
print(f"Firmware: {info.firmware_version}")
```
### Historical Data
```python
async with device:
history = await device.get_historical_data()
for entry in history[-5:]: # Last 5 entries
print(f"{entry.timestamp}: {entry.sensor_data}")
```
### Continuous Monitoring
```python
import asyncio
from datetime import datetime
from flowercare import FlowerCareScanner
async def monitor_device(device):
while True:
try:
async with device:
while True:
data = await device.read_sensor_data()
timestamp = datetime.now().strftime("%H:%M:%S")
print(f"[{timestamp}] {data}")
await asyncio.sleep(60) # Read every minute
except Exception as e:
print(f"Error: {e}")
await asyncio.sleep(5) # Retry after 5 seconds
async def main():
scanner = FlowerCareScanner()
devices = await scanner.scan_for_devices()
# Monitor all found devices
tasks = [monitor_device(device) for device in devices]
await asyncio.gather(*tasks)
asyncio.run(main())
```
## API Reference
### FlowerCareScanner
- `scan_for_devices(timeout=10.0)`: Scan for FlowerCare devices
- `find_device_by_mac(mac_address, timeout=10.0)`: Find specific device by MAC address
- `scan_continuously(callback, timeout=None)`: Continuous scanning with callback
- `scan_stream(timeout=None)`: Async generator for device discovery
### FlowerCareDevice
- `connect(timeout=10.0)`: Connect to device
- `disconnect()`: Disconnect from device
- `read_sensor_data()`: Read current sensor measurements
- `get_device_info()`: Get device information (name, MAC, battery, firmware)
- `get_historical_data()`: Get stored historical measurements
- `blink_led()`: Make device LED blink
### Data Models
#### SensorData
- `temperature`: Temperature in Celsius
- `brightness`: Light intensity in lux
- `moisture`: Soil moisture percentage
- `conductivity`: Soil conductivity in µS/cm
- `timestamp`: Measurement timestamp
#### DeviceInfo
- `name`: Device name
- `mac_address`: MAC address
- `firmware_version`: Firmware version
- `battery_level`: Battery level percentage
## Error Handling
The library provides specific exception types:
```python
from flowercare.exceptions import (
FlowerCareError, # Base exception
ConnectionError, # Connection failures
DeviceError, # Device operation errors
DataParsingError, # Data parsing errors
TimeoutError # Operation timeouts
)
try:
async with device:
data = await device.read_sensor_data()
except ConnectionError as e:
print(f"Failed to connect: {e}")
except DeviceError as e:
print(f"Device error: {e}")
```
## Logging
Enable logging to see detailed operation information:
```python
from flowercare.logging import setup_logging
setup_logging("DEBUG") # Enable debug logging
```
## Examples
See the `examples/` directory for more comprehensive examples:
- `basic_usage.py`: Simple device connection and data reading
- `continuous_monitoring.py`: Continuous monitoring of multiple devices
- `historical_data.py`: Historical data retrieval and CSV export
## Troubleshooting
### Permission Issues (Linux)
```bash
sudo setcap cap_net_raw+eip $(eval readlink -f `which python`)
```
### Bluetooth Not Available
Ensure your system has Bluetooth Low Energy support and the adapter is enabled.
### Device Not Found
- Ensure the FlowerCare device is nearby and not connected to another app
- Try increasing the scan timeout
- Check that the device battery is not depleted
## License
This project is licensed under the MIT License.
## Contributing
Contributions are welcome! Please feel free to submit issues and enhancement requests.
Raw data
{
"_id": null,
"home_page": "https://github.com/eljhr9/pyflowercare",
"name": "pyflowercare",
"maintainer": null,
"docs_url": null,
"requires_python": "<3.13,>=3.9",
"maintainer_email": null,
"keywords": "flowercare, xiaomi, miflora, bluetooth, plant, sensor, ble",
"author": "Ilya Redkolis",
"author_email": "illyaredkolis@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/71/59/2b2f1e68413e125e34237d09878760088f90b609edae8956fdd02652291d/pyflowercare-0.1.1.tar.gz",
"platform": null,
"description": "# PyFlowerCare\n\nA Python library for communicating with FlowerCare (Xiaomi MiFlora) Bluetooth plant sensors.\n\n## Features\n\n- **Device Discovery**: Scan and discover FlowerCare devices via Bluetooth Low Energy\n- **Real-time Sensor Data**: Read temperature, brightness, soil moisture, and conductivity\n- **Historical Data**: Access stored historical measurements from the device\n- **Device Management**: Connect, disconnect, and manage multiple devices\n- **Async Support**: Full asyncio support for non-blocking operations\n- **Error Handling**: Comprehensive exception handling with meaningful error messages\n\n## Installation\n\n```bash\npip install pyflowercare\n```\n\n## Requirements\n\n- Python 3.9+\n- Bluetooth Low Energy support\n- Linux/macOS/Windows with Bluetooth adapter\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom flowercare import FlowerCareScanner\n\nasync def main():\n scanner = FlowerCareScanner()\n \n # Scan for devices\n devices = await scanner.scan_for_devices(timeout=10.0)\n \n if devices:\n device = devices[0]\n \n # Connect and read data\n async with device:\n sensor_data = await device.read_sensor_data()\n print(f\"Temperature: {sensor_data.temperature}\u00b0C\")\n print(f\"Brightness: {sensor_data.brightness} lux\")\n print(f\"Moisture: {sensor_data.moisture}%\")\n print(f\"Conductivity: {sensor_data.conductivity} \u00b5S/cm\")\n\nasyncio.run(main())\n```\n\n### Device Information\n\n```python\nasync with device:\n info = await device.get_device_info()\n print(f\"Device: {info.name}\")\n print(f\"MAC: {info.mac_address}\")\n print(f\"Battery: {info.battery_level}%\")\n print(f\"Firmware: {info.firmware_version}\")\n```\n\n### Historical Data\n\n```python\nasync with device:\n history = await device.get_historical_data()\n \n for entry in history[-5:]: # Last 5 entries\n print(f\"{entry.timestamp}: {entry.sensor_data}\")\n```\n\n### Continuous Monitoring\n\n```python\nimport asyncio\nfrom datetime import datetime\nfrom flowercare import FlowerCareScanner\n\nasync def monitor_device(device):\n while True:\n try:\n async with device:\n while True:\n data = await device.read_sensor_data()\n timestamp = datetime.now().strftime(\"%H:%M:%S\")\n print(f\"[{timestamp}] {data}\")\n await asyncio.sleep(60) # Read every minute\n except Exception as e:\n print(f\"Error: {e}\")\n await asyncio.sleep(5) # Retry after 5 seconds\n\nasync def main():\n scanner = FlowerCareScanner()\n devices = await scanner.scan_for_devices()\n \n # Monitor all found devices\n tasks = [monitor_device(device) for device in devices]\n await asyncio.gather(*tasks)\n\nasyncio.run(main())\n```\n\n## API Reference\n\n### FlowerCareScanner\n\n- `scan_for_devices(timeout=10.0)`: Scan for FlowerCare devices\n- `find_device_by_mac(mac_address, timeout=10.0)`: Find specific device by MAC address\n- `scan_continuously(callback, timeout=None)`: Continuous scanning with callback\n- `scan_stream(timeout=None)`: Async generator for device discovery\n\n### FlowerCareDevice\n\n- `connect(timeout=10.0)`: Connect to device\n- `disconnect()`: Disconnect from device\n- `read_sensor_data()`: Read current sensor measurements\n- `get_device_info()`: Get device information (name, MAC, battery, firmware)\n- `get_historical_data()`: Get stored historical measurements\n- `blink_led()`: Make device LED blink\n\n### Data Models\n\n#### SensorData\n- `temperature`: Temperature in Celsius\n- `brightness`: Light intensity in lux\n- `moisture`: Soil moisture percentage\n- `conductivity`: Soil conductivity in \u00b5S/cm\n- `timestamp`: Measurement timestamp\n\n#### DeviceInfo\n- `name`: Device name\n- `mac_address`: MAC address\n- `firmware_version`: Firmware version\n- `battery_level`: Battery level percentage\n\n## Error Handling\n\nThe library provides specific exception types:\n\n```python\nfrom flowercare.exceptions import (\n FlowerCareError, # Base exception\n ConnectionError, # Connection failures\n DeviceError, # Device operation errors\n DataParsingError, # Data parsing errors\n TimeoutError # Operation timeouts\n)\n\ntry:\n async with device:\n data = await device.read_sensor_data()\nexcept ConnectionError as e:\n print(f\"Failed to connect: {e}\")\nexcept DeviceError as e:\n print(f\"Device error: {e}\")\n```\n\n## Logging\n\nEnable logging to see detailed operation information:\n\n```python\nfrom flowercare.logging import setup_logging\n\nsetup_logging(\"DEBUG\") # Enable debug logging\n```\n\n## Examples\n\nSee the `examples/` directory for more comprehensive examples:\n\n- `basic_usage.py`: Simple device connection and data reading\n- `continuous_monitoring.py`: Continuous monitoring of multiple devices\n- `historical_data.py`: Historical data retrieval and CSV export\n\n## Troubleshooting\n\n### Permission Issues (Linux)\n```bash\nsudo setcap cap_net_raw+eip $(eval readlink -f `which python`)\n```\n\n### Bluetooth Not Available\nEnsure your system has Bluetooth Low Energy support and the adapter is enabled.\n\n### Device Not Found\n- Ensure the FlowerCare device is nearby and not connected to another app\n- Try increasing the scan timeout\n- Check that the device battery is not depleted\n\n## License\n\nThis project is licensed under the MIT License.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues and enhancement requests.",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python library for communicating with FlowerCare (Xiaomi MiFlora) Bluetooth plant sensors",
"version": "0.1.1",
"project_urls": {
"Homepage": "https://github.com/eljhr9/pyflowercare",
"Repository": "https://github.com/eljhr9/pyflowercare"
},
"split_keywords": [
"flowercare",
" xiaomi",
" miflora",
" bluetooth",
" plant",
" sensor",
" ble"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "a5840e26e0f2946761ffe01f682812380a3975faea7fe070bacffb386014e38c",
"md5": "ab94911fd45aab730112051e0784db27",
"sha256": "b08846c2c44347e2cd90971dafa8f1ad7257c20b955aebb232ee9ff8dc90190e"
},
"downloads": -1,
"filename": "pyflowercare-0.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "ab94911fd45aab730112051e0784db27",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<3.13,>=3.9",
"size": 11110,
"upload_time": "2025-08-27T13:51:58",
"upload_time_iso_8601": "2025-08-27T13:51:58.257460Z",
"url": "https://files.pythonhosted.org/packages/a5/84/0e26e0f2946761ffe01f682812380a3975faea7fe070bacffb386014e38c/pyflowercare-0.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "71592b2f1e68413e125e34237d09878760088f90b609edae8956fdd02652291d",
"md5": "31d4e46f976cf398ee08047fce2031b9",
"sha256": "37b1fd4683fb3b054de67ebc2f4dc31f685f69fbe94fe55f83590819b3118ebf"
},
"downloads": -1,
"filename": "pyflowercare-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "31d4e46f976cf398ee08047fce2031b9",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<3.13,>=3.9",
"size": 12141,
"upload_time": "2025-08-27T13:51:59",
"upload_time_iso_8601": "2025-08-27T13:51:59.371761Z",
"url": "https://files.pythonhosted.org/packages/71/59/2b2f1e68413e125e34237d09878760088f90b609edae8956fdd02652291d/pyflowercare-0.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-27 13:51:59",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "eljhr9",
"github_project": "pyflowercare",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "pyflowercare"
}