piwave 2.0.8__py3-none-any.whl → 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,743 @@
1
+ Metadata-Version: 2.4
2
+ Name: piwave
3
+ Version: 2.1.0
4
+ Summary: A python module to broadcast radio waves with your Raspberry Pi.
5
+ Home-page: https://github.com/douxxtech/piwave
6
+ Author: Douxx
7
+ Author-email: douxx@douxx.tech
8
+ License: GPL-3.0-or-later
9
+ Project-URL: Bug Reports, https://github.com/douxxtech/piwave/issues
10
+ Project-URL: Source, https://github.com/douxxtech/piwave
11
+ Keywords: raspberry pi,radio,fm,rds,streaming,audio,broadcast
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Requires-Python: >=3.7
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=6.0; extra == "dev"
23
+ Requires-Dist: pytest-cov>=2.0; extra == "dev"
24
+ Requires-Dist: black>=22.0; extra == "dev"
25
+ Requires-Dist: flake8>=4.0; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ <div align=center>
29
+ <img alt="PiWave image" src="https://piwave.xyz/static/img/logo.png"/>
30
+ <h1>PiWave</h1>
31
+ </div>
32
+
33
+ **PiWave** is a Python module designed to manage and control your Raspberry Pi radio using multiple FM transmission backends. It provides a unified interface for broadcasting audio files with multiple backends support and RDS (Radio Data System) support.
34
+
35
+ ## Features
36
+
37
+ - **Multi-Backend Architecture**: Supports multiple backends for different actions
38
+ - **Wide Frequency Support**: 1-250 MHz coverage through different backends
39
+ - **RDS Support**: Program Service, Radio Text, and Program Identifier broadcasting
40
+ - **Smart Backend Selection**: Automatically chooses the best backend to suit your needs
41
+ - **Audio Format Support**: Converts most audio formats (MP3, FLAC, M4A, etc.) to WAV
42
+ - **Real-time Settings Updates**: Change frequency, RDS data, and settings without restart
43
+ - **Advanced Playback Control**: Play, pause, resume, stop, and loop functionality
44
+ - **CLI Interface**: Command-line tools for backend management and broadcasting
45
+ - **Detailed Logging**: Debug mode with comprehensive error handling
46
+ - **Event Callbacks**: Custom handlers for track changes and errors
47
+ - **Non-blocking Operation**: Threading-based playback with status monitoring
48
+
49
+ ## Supported Backends
50
+
51
+ ### PiFmRds Backend
52
+ - **Frequency Range**: 80.0 - 108.0 MHz (Standard FM band)
53
+ - **RDS Support**: ✅ Full support (PS, RT, PI)
54
+ - **Repository**: [ChristopheJacquet/PiFmRds](https://github.com/ChristopheJacquet/PiFmRds)
55
+ - **Best For**: Standard FM broadcasting with RDS features
56
+
57
+ ### FmTransmitter Backend
58
+ - **Frequency Range**: 1.0 - 250.0 MHz (Extended range)
59
+ - **RDS Support**: ❌ No RDS support
60
+ - **Repository**: [markondej/fm_transmitter](https://github.com/markondej/fm_transmitter)
61
+ - **Best For**: Non-standard frequencies and experimental broadcasting
62
+
63
+ ## Hardware Installation
64
+
65
+ To use PiWave for broadcasting, you need to set up the hardware correctly:
66
+
67
+ 1. **Connect the Antenna**:
68
+ - Attach a cable or antenna to GPIO 4 (Pin 7) on the Raspberry Pi
69
+ - Ensure secure connection for optimal signal quality
70
+ - Use appropriate antenna length for your target frequency
71
+
72
+ 2. **GPIO Configuration**:
73
+ - GPIO 4 (Pin 7) is used for FM signal output
74
+ - No additional hardware modifications required
75
+
76
+ ## Installation
77
+
78
+ > [!WARNING]
79
+ > **Legal Disclaimer**: Broadcasting radio signals may be subject to local regulations and laws. It is your responsibility to ensure compliance with all applicable legal requirements in your area. Unauthorized broadcasting may result in legal consequences, including fines or penalties.
80
+ >
81
+ > **Liability**: The author is not responsible for any damage, loss, or legal issues arising from the use of this software. Users accept all risks and liabilities associated with operation and broadcasting capabilities.
82
+
83
+ ### Quick Installation (Recommended)
84
+
85
+ Use the automated installer script:
86
+
87
+ ```bash
88
+ curl -sL https://setup.piwave.xyz/ | sudo bash
89
+ ```
90
+
91
+ This installs PiWave dependencies and the PiFmRds backend automatically.
92
+
93
+ #### Advanced Installation Options
94
+
95
+ ```bash
96
+ # Install with fm_transmitter backend (may affect system stability)
97
+ curl -sL https://setup.piwave.xyz/ | sudo bash -s -- --install_fmt
98
+
99
+ # Skip confirmation prompts
100
+ curl -sL https://setup.piwave.xyz/ | sudo bash -s -- --install_fmt --no-wait
101
+ ```
102
+
103
+ #### Uninstallation
104
+
105
+ ```bash
106
+ curl -sL https://setup.piwave.xyz/uninstall | sudo bash
107
+ ```
108
+
109
+ ### Manual Installation
110
+
111
+ 1. **Install Dependencies**:
112
+ ```bash
113
+ sudo apt update
114
+ sudo apt install -y python3 python3-pip ffmpeg git make libsndfile1-dev
115
+ ```
116
+
117
+ 2. **Install PiWave**:
118
+ ```bash
119
+ # Create virtual environment (recommended)
120
+ python3 -m venv ~/piwave-env
121
+ source ~/piwave-env/bin/activate
122
+
123
+ # Install PiWave
124
+ pip install git+https://github.com/douxxtech/piwave.git
125
+ ```
126
+
127
+ 3. **Install Backends**:
128
+
129
+ **PiFmRds** (Recommended):
130
+ ```bash
131
+ git clone https://github.com/ChristopheJacquet/PiFmRds /opt/PiWave/PiFmRds
132
+ cd /opt/PiWave/PiFmRds/src
133
+ make
134
+ ```
135
+
136
+ **FmTransmitter** (Optional):
137
+ ```bash
138
+ sudo apt install -y libraspberrypi-dev
139
+ git clone https://github.com/markondej/fm_transmitter /opt/PiWave/fm_transmitter
140
+ cd /opt/PiWave/fm_transmitter
141
+ make
142
+ ```
143
+
144
+ ## Backend Management
145
+
146
+ ### CLI Commands
147
+
148
+ ```bash
149
+ # Search for available backends on system
150
+ python3 -m piwave search
151
+
152
+ # List cached backends
153
+ python3 -m piwave list
154
+
155
+ # Manually add backend executable path
156
+ python3 -m piwave add pi_fm_rds /path/to/pi_fm_rds
157
+
158
+ # Show package information
159
+ python3 -m piwave info
160
+
161
+ # Broadcast a file directly
162
+ python3 -m piwave broadcast song.mp3 --frequency 101.5 --ps "MyRadio"
163
+ ```
164
+
165
+ ### Programmatic Backend Discovery
166
+
167
+ ```python
168
+ from piwave.backends import discover_backends, list_backends, search_backends
169
+
170
+ # Load cached backends
171
+ discover_backends()
172
+
173
+ # Search for new backends (ignores cache)
174
+ search_backends()
175
+
176
+ # List available backends with details
177
+ backends_info = list_backends()
178
+ ```
179
+
180
+ ## Quick Start
181
+
182
+ ### Basic Usage
183
+
184
+ ```python
185
+ from piwave import PiWave
186
+
187
+ # Initialize with automatic backend selection
188
+ pw = PiWave(
189
+ frequency=90.0,
190
+ ps="MyRadio",
191
+ rt="Playing great music",
192
+ pi="ABCD",
193
+ debug=True
194
+ )
195
+
196
+ # Play a single audio file
197
+ pw.play("song.mp3")
198
+
199
+ # Stop playback
200
+ pw.stop()
201
+ ```
202
+
203
+ ### Backend Selection
204
+
205
+ ```python
206
+ from piwave import PiWave
207
+
208
+ # Automatic selection (recommended)
209
+ pw = PiWave(frequency=95.0, backend="auto")
210
+
211
+ # Force specific backend
212
+ pw = PiWave(frequency=95.0, backend="pi_fm_rds")
213
+
214
+ # Extended frequency range with fm_transmitter
215
+ pw = PiWave(frequency=150.0, backend="fm_transmitter")
216
+ ```
217
+
218
+ ### Real-time Settings Updates
219
+
220
+ ```python
221
+ from piwave import PiWave
222
+
223
+ pw = PiWave()
224
+
225
+ # Update multiple settings at once
226
+ pw.update(
227
+ frequency=101.5,
228
+ ps="NewName",
229
+ rt="Updated radio text",
230
+ debug=True
231
+ )
232
+
233
+ # Individual setting updates
234
+ pw.update(frequency=102.1)
235
+ pw.update(ps="Radio2024")
236
+ ```
237
+
238
+ ### Advanced Playback Control
239
+
240
+ ```python
241
+ from piwave import PiWave
242
+
243
+ pw = PiWave(frequency=95.0, loop=True)
244
+
245
+ # Playback control
246
+ pw.play("music.mp3")
247
+ pw.pause()
248
+ pw.resume()
249
+ pw.stop()
250
+
251
+ # Status monitoring
252
+ status = pw.get_status()
253
+ print(f"Playing: {status['is_playing']}")
254
+ print(f"Current backend: {status['current_backend']}")
255
+ print(f"Backend supports RDS: {status['backend_supports_rds']}")
256
+ print(f"Frequency range: {status['backend_frequency_range']}")
257
+ ```
258
+
259
+ ## Complete Examples
260
+
261
+ <details>
262
+ <summary>Click to expand examples</summary>
263
+
264
+ ### Multi-Backend Radio Station
265
+
266
+ ```python
267
+ from piwave import PiWave
268
+ import os
269
+ import time
270
+
271
+ def smart_radio_station():
272
+ """Automatically selects best backend for each frequency"""
273
+
274
+ stations = [
275
+ {"freq": 88.5, "name": "Jazz FM", "file": "jazz.mp3"},
276
+ {"freq": 101.5, "name": "Rock Radio", "file": "rock.mp3"},
277
+ {"freq": 150.0, "name": "Experimental", "file": "experimental.wav"}
278
+ ]
279
+
280
+ for station in stations:
281
+ try:
282
+ # PiWave automatically selects the best backend
283
+ pw = PiWave(
284
+ frequency=station["freq"],
285
+ ps=station["name"][:8], # Max 8 chars
286
+ rt=f"Broadcasting {station['name']}",
287
+ backend="auto" # Let PiWave choose
288
+ )
289
+
290
+ print(f"Starting {station['name']} on {station['freq']}MHz")
291
+ print(f"Using backend: {pw.get_status()['current_backend']}")
292
+
293
+ if os.path.exists(station["file"]):
294
+ pw.play(station["file"])
295
+
296
+ # Wait for completion or user interrupt
297
+ while pw.get_status()['is_playing']:
298
+ time.sleep(1)
299
+
300
+ print(f"{station['name']} completed")
301
+ else:
302
+ print(f"File {station['file']} not found")
303
+
304
+ pw.cleanup()
305
+
306
+ except Exception as e:
307
+ print(f"Error with {station['name']}: {e}")
308
+
309
+ if __name__ == "__main__":
310
+ smart_radio_station()
311
+ ```
312
+
313
+ ### Text-to-Speech Radio with Backend Selection
314
+
315
+ ```python
316
+ from gtts import gTTS
317
+ from piwave import PiWave
318
+ from pydub import AudioSegment
319
+ import os
320
+ import sys
321
+ import time
322
+
323
+ def tts_radio():
324
+ """Text-to-speech radio with automatic backend selection using update() method"""
325
+
326
+ print("=" * 50)
327
+ print("TTS Radio, original: https://git.new/SEdemCA")
328
+ print("=" * 50)
329
+
330
+ pw = None
331
+ wav_file = "tts_radio.wav"
332
+
333
+ try:
334
+ # Initialize PiWave once with default settings
335
+ print("Initializing PiWave...")
336
+ pw = PiWave(
337
+ frequency=90.0, # Default frequency
338
+ ps="TTS-FM",
339
+ rt="Text-to-Speech Radio",
340
+ backend="auto",
341
+ silent=False
342
+ )
343
+
344
+ print("PiWave initialized successfully!")
345
+ print(f"Initial backend: {pw.get_status()['current_backend']}")
346
+ print("=" * 50)
347
+
348
+ while True:
349
+ print("\n" + "=" * 30)
350
+ text = input("Text to broadcast: ").strip()
351
+ if not text:
352
+ print("No text entered, skipping...\n")
353
+ continue
354
+
355
+ try:
356
+ freq = float(input("Frequency (MHz): "))
357
+ except ValueError:
358
+ print("Invalid frequency, please enter a number.\n")
359
+ continue
360
+
361
+ # Let user choose backend or use auto
362
+ backend_choice = input("Backend (auto/pi_fm_rds/fm_transmitter) [auto]: ").strip()
363
+ if not backend_choice:
364
+ backend_choice = "auto"
365
+
366
+ # Generate TTS
367
+ print("Generating speech...")
368
+ mp3_file = "temp_tts.mp3"
369
+ tts = gTTS(text=text, lang="en", slow=False)
370
+ tts.save(mp3_file)
371
+
372
+ # Convert to WAV
373
+ sound = AudioSegment.from_mp3(mp3_file)
374
+ sound.export(wav_file, format="wav")
375
+ os.remove(mp3_file)
376
+
377
+ try:
378
+ # update pw settings
379
+
380
+ update_params = {
381
+ 'frequency': freq,
382
+ 'rt': text[:64]
383
+ }
384
+
385
+ update_params['backend'] = backend_choice
386
+
387
+ print("Updating broadcast settings...")
388
+ pw.update(**update_params)
389
+
390
+ status = pw.get_status()
391
+ print(f"\nBroadcast Configuration:")
392
+ print(f"Frequency: {freq}MHz")
393
+ print(f"Backend: {status['current_backend']}")
394
+ print(f"RDS Support: {'Yes' if status['backend_supports_rds'] else 'No'}")
395
+ print(f"Text: {text}")
396
+ print("=" * 50)
397
+
398
+ pw.play(wav_file)
399
+ print("Broadcasting! Press Ctrl+C to stop...\n")
400
+
401
+ # Wait for completion
402
+ while pw.get_status()['is_playing']:
403
+ time.sleep(0.5)
404
+
405
+ print("Broadcast completed!\n")
406
+
407
+ except Exception as e:
408
+ print(f"Update/Broadcast error: {e}")
409
+ print("Continuing with current settings...\n")
410
+ continue
411
+
412
+ except KeyboardInterrupt:
413
+ print("\nStopped by user.")
414
+ except Exception as e:
415
+ print(f"Initialization error: {e}")
416
+ print("Make sure you're running on a Raspberry Pi as root with PiWave dependencies installed.")
417
+ finally:
418
+ if pw:
419
+ pw.cleanup()
420
+
421
+ # Cleanup temp files
422
+ for temp_file in [wav_file, "temp_tts.mp3"]:
423
+ if os.path.exists(temp_file):
424
+ os.remove(temp_file)
425
+
426
+ print("Cleanup completed.")
427
+
428
+ if __name__ == "__main__":
429
+ tts_radio()
430
+ ```
431
+
432
+ </details>
433
+
434
+ ## API Reference
435
+
436
+ <details>
437
+ <summary>Click to expand API reference</summary>
438
+
439
+
440
+ ### PiWave Class
441
+
442
+ #### Initialization
443
+
444
+ ```python
445
+ PiWave(
446
+ frequency=90.0, # Broadcast frequency (1.0-250.0 MHz)
447
+ ps="PiWave", # Program Service name (max 8 chars)
448
+ rt="PiWave: ...", # Radio Text (max 64 chars)
449
+ pi="FFFF", # Program Identifier (4 hex digits)
450
+ debug=False, # Enable debug logging
451
+ silent=False, # Disable all logging
452
+ loop=False, # Loop current track continuously
453
+ backend="auto", # Backend selection ("auto", "pi_fm_rds", "fm_transmitter")
454
+ on_track_change=None, # Callback for track changes
455
+ on_error=None # Callback for errors
456
+ )
457
+ ```
458
+
459
+ #### Core Methods
460
+
461
+ ##### `play(file_path: str) -> bool`
462
+ Start playing an audio file with automatic format conversion.
463
+
464
+ ```python
465
+ pw.play("song.mp3") # Returns True if started successfully
466
+ ```
467
+
468
+ ##### `stop()`
469
+ Stop all playback and clean up processes.
470
+
471
+ ```python
472
+ pw.stop()
473
+ ```
474
+
475
+ ##### `pause()` / `resume()`
476
+ Pause and resume playback control.
477
+
478
+ ```python
479
+ pw.pause()
480
+ pw.resume()
481
+ ```
482
+
483
+ ##### `update(**kwargs)`
484
+ Update settings in real-time. Accepts any initialization parameter.
485
+
486
+ ```python
487
+ pw.update(frequency=101.5, ps="NewName", backend="fm_transmitter")
488
+ ```
489
+
490
+ ##### `get_status() -> dict`
491
+ Get comprehensive status information.
492
+
493
+ ```python
494
+ status = pw.get_status()
495
+ # Returns:
496
+ {
497
+ 'is_playing': bool,
498
+ 'frequency': float,
499
+ 'current_file': str|None,
500
+ 'current_backend': str,
501
+ 'backend_frequency_range': str,
502
+ 'backend_supports_rds': bool,
503
+ 'available_backends': list,
504
+ 'ps': str,
505
+ 'rt': str,
506
+ 'pi': str,
507
+ 'loop': bool
508
+ }
509
+ ```
510
+
511
+ ##### `cleanup()`
512
+ Clean up resources and temporary files.
513
+
514
+ ```python
515
+ pw.cleanup() # Called automatically on object destruction
516
+ ```
517
+
518
+ ### Backend Management
519
+
520
+ #### Discovery Functions
521
+
522
+ ```python
523
+ from piwave.backends import discover_backends, search_backends, list_backends
524
+
525
+ # Load cached backend availability
526
+ discover_backends()
527
+
528
+ # Perform fresh search (updates cache)
529
+ search_backends()
530
+
531
+ # List available backends with details
532
+ backend_info = list_backends()
533
+ ```
534
+
535
+ #### Backend Selection
536
+
537
+ ```python
538
+ from piwave.backends import get_best_backend
539
+
540
+ # Get best backend for specific frequency
541
+ backend_name = get_best_backend("file_broadcast", 95.0)
542
+ ```
543
+
544
+ ### Command Line Interface
545
+
546
+ ```bash
547
+ # Backend management
548
+ python3 -m piwave search # Search for backends
549
+ python3 -m piwave list # List cached backends
550
+ python3 -m piwave add pi_fm_rds /path/exe # Add backend path
551
+ python3 -m piwave info # Package information
552
+
553
+ # Direct broadcasting
554
+ python3 -m piwave broadcast file.mp3 \
555
+ --frequency 101.5 \
556
+ --ps "MyRadio" \
557
+ --rt "Great Music" \
558
+ --pi "ABCD" \
559
+ --backend auto \
560
+ --loop \
561
+ --debug
562
+ ```
563
+
564
+ ## Error Handling
565
+
566
+ PiWave includes comprehensive error handling:
567
+
568
+ - **Environment Validation**: Raspberry Pi and root access checks
569
+ - **Backend Validation**: Automatic detection and compatibility verification
570
+ - **Frequency Validation**: Ensures frequency is within backend's supported range
571
+ - **File Validation**: Checks file existence and format compatibility
572
+ - **Process Management**: Clean process termination and resource cleanup
573
+ - **Exception Callbacks**: Custom error handlers for applications
574
+
575
+ ### Common Error Scenarios
576
+
577
+ ```python
578
+ from piwave import PiWave, PiWaveError
579
+
580
+ try:
581
+ pw = PiWave(frequency=50.0, backend="pi_fm_rds") # Outside range
582
+ except PiWaveError as e:
583
+ print(f"Configuration error: {e}")
584
+ # Try with auto backend selection
585
+ pw = PiWave(frequency=50.0, backend="auto")
586
+ ```
587
+
588
+ ## Backend Development
589
+
590
+ ### Creating Custom Backends
591
+
592
+ ```python
593
+ from piwave.backends.base import Backend
594
+
595
+ class CustomBackend(Backend):
596
+ @property
597
+ def name(self):
598
+ return "custom_backend"
599
+
600
+ @property
601
+ def frequency_range(self):
602
+ return (50.0, 200.0) # MHz range
603
+
604
+ @property
605
+ def supports_rds(self):
606
+ return True # RDS capability
607
+
608
+ def _get_executable_name(self):
609
+ return "my_transmitter"
610
+
611
+ def _get_search_paths(self):
612
+ return ["/opt", "/usr/local/bin", "/usr/bin"]
613
+
614
+ def build_command(self, wav_file: str):
615
+ cmd = ['sudo', self.required_executable, '-f', str(self.frequency)]
616
+ if self.supports_rds and self.ps:
617
+ cmd.extend(['-ps', self.ps])
618
+ cmd.append(wav_file)
619
+ return cmd
620
+ ```
621
+
622
+ ### Backend Registration
623
+
624
+ ```python
625
+ from piwave.backends import backend_classes
626
+
627
+ # Register custom backend
628
+ backend_classes["custom_backend"] = CustomBackend
629
+
630
+ # Re-discover backends
631
+ from piwave.backends import discover_backends
632
+ discover_backends()
633
+ ```
634
+
635
+ </details>
636
+
637
+ ## Troubleshooting
638
+
639
+ ### Common Issues
640
+
641
+ 1. **"No suitable backend found"**
642
+ ```bash
643
+ python3 -m piwave search # Refresh backend cache
644
+ ```
645
+
646
+ 2. **"Backend doesn't support frequency"**
647
+ ```python
648
+ # Check supported ranges
649
+ python3 -m piwave list
650
+
651
+ # Use auto selection
652
+ pw = PiWave(frequency=your_freq, backend="auto")
653
+ ```
654
+
655
+ 3. **"Process failed to start"**
656
+ - Ensure running as root: `sudo python3 your_script.py`
657
+ - Verify backend installation: `python3 -m piwave list`
658
+ - Check executable permissions
659
+
660
+ 4. **Audio conversion issues**
661
+ - Install FFmpeg: `sudo apt install ffmpeg`
662
+ - Check file format support
663
+ - Verify file permissions
664
+
665
+ ### Debug Mode
666
+
667
+ Enable comprehensive logging:
668
+
669
+ ```python
670
+ pw = PiWave(debug=True)
671
+ # or
672
+ pw.update(debug=True)
673
+ ```
674
+
675
+ ### Backend Path Issues
676
+
677
+ Manually specify backend paths:
678
+
679
+ ```bash
680
+ # Find backend executable
681
+ sudo find /opt -name "pi_fm_rds" -type f
682
+
683
+ # Add to PiWave
684
+ python3 -m piwave add pi_fm_rds /opt/PiWave/PiFmRds/src/pi_fm_rds
685
+ ```
686
+
687
+ ## Performance Notes
688
+
689
+ - **Backend Selection**: `pi_fm_rds` generally provides better stability for standard FM frequencies
690
+ - **Audio Conversion**: WAV files play immediately; other formats require conversion time
691
+ - **Memory Usage**: Large audio files are streamed, not loaded entirely into memory
692
+ - **CPU Impact**: FM transmission is CPU-intensive; avoid other heavy processes during broadcast
693
+
694
+ ## Requirements
695
+
696
+ - Raspberry Pi (any model with GPIO)
697
+ - Root access (`sudo`)
698
+ - Python 3.7+
699
+ - FFmpeg for audio conversion
700
+ - At least one backend installed (PiFmRds or fm_transmitter)
701
+
702
+ ### System Dependencies
703
+
704
+ ```bash
705
+ sudo apt install -y python3 python3-pip ffmpeg git make libsndfile1-dev
706
+ ```
707
+
708
+ ### Optional Dependencies
709
+
710
+ ```bash
711
+ # For extended frequency range
712
+ sudo apt install -y libraspberrypi-dev
713
+
714
+ # For Python virtual environment (recommended)
715
+ sudo apt install -y python3-venv
716
+ ```
717
+
718
+ ## License
719
+
720
+ PiWave is licensed under the GNU General Public License (GPL) v3.0. See the [LICENSE](LICENSE) file for details.
721
+
722
+ ## Contributing
723
+
724
+ Contributions are welcome! Areas for contribution:
725
+
726
+ - Additional backend implementations
727
+ - Improved frequency range detection
728
+ - Enhanced RDS functionality
729
+ - Performance optimizations
730
+ - Documentation improvements
731
+
732
+ Please submit pull requests or open issues on [GitHub](https://github.com/douxxtech/piwave/issues).
733
+
734
+ ## Acknowledgments
735
+
736
+ - [ChristopheJacquet/PiFmRds](https://github.com/ChristopheJacquet/PiFmRds) - Primary FM/RDS backend
737
+ - [markondej/fm_transmitter](https://github.com/markondej/fm_transmitter) - Extended frequency backend
738
+
739
+ ---
740
+
741
+ **PiWave** - FM Broadcasting module for Raspberry Pi
742
+
743
+ ![Made by Douxx](https://madeby.douxx.tech)