Représentation des données¶
Bits, bytes, et types numériques en IoT
Le bit et l'octet¶
Bit : Plus petite unité d'information (0 ou 1)
Octet (Byte) : 8 bits = 1 octet
text
1 byte = 8 bits
11010101 = 1 octettypescript
En anglais : 1 byte = 8 bits En français : 1 octet = 8 bits
ExploreIOT : Un capteur LoRaWAN envoie 11 octets minimum.
Word et Multi-byte¶
Word : Groupement de bytes selon l'architecture
- 16-bit system : 1 word = 2 bytes
- 32-bit system : 1 word = 4 bytes
- 64-bit system : 1 word = 8 bytes
```python import struct
Format: '>HH' = big-endian, 2 unsigned shorts (16-bit each)¶
payload = struct.pack('>HH', 2450, 65) # 4 octets (2 words de 2 bytes) print(len(payload)) # 4 print(payload.hex()) # 09b20041 ```typescript
Entiers non signés (unsigned)¶
Plage : 0 à 2^n - 1
- uint8 : 0 à 255 (1 octet)
- uint16 : 0 à 65,535 (2 octets)
- uint32 : 0 à 4,294,967,295 (4 octets)
- uint64 : 0 à 18,446,744,073,709,551,615 (8 octets)
```python import struct
uint16 = 2 octets, non signé¶
temp_raw = 2450 payload = struct.pack('>H', temp_raw) # '>H' = big-endian unsigned short print(f"Bytes: {payload.hex()}") # 09b2 print(f"Length: {len(payload)} octets") # 2 ```typescript
Entiers signés (signed)¶
Plage : -(2^(n-1)) à 2^(n-1) - 1
- int8 : -128 à 127 (1 octet)
- int16 : -32,768 à 32,767 (2 octets)
- int32 : -2,147,483,648 à 2,147,483,647 (4 octets)
Représentation : Complément à deux.
```python import struct
int16 = 2 octets, signé¶
temp = -5 payload = struct.pack('>h', temp) # '>h' = big-endian signed short print(f"Bytes: {payload.hex()}") # fffb ```bash
Overflow : Débordement¶
Integer overflow : Quand la valeur dépasse la plage du type.
```python import struct
uint8 : 0-255¶
value = 256 packed = struct.pack('>B', value % 256) # B = unsigned char (uint8) print(f"256 % 256 = {256 % 256}") # 0 (wraparound)
ExploreIOT exemple : capteur > 255¶
temp_int = 301
Si on utilise uint8 sans conversion : overflow !¶
temp_uint8 = temp_int % 256 print(f"301 as uint8: {temp_uint8}") # 45 ```json
Solution IoT : Utiliser uint16, uint32, ou compression (temp × 100).
ExploreIOT : Température en uint16¶
Capteur de température = -40°C à +85°C.
Problème : -40 est négatif. Besoin de int16 ou offset.
Solution 1 : int16 (signé)
```python import struct
temp_celsius = -5.25 temp_raw = int(temp_celsius * 100) # -525 payload = struct.pack('>h', temp_raw) # big-endian signed short print(f"Temp -5.25°C -> bytes: {payload.hex()}") # fdef ```python
Solution 2 : uint16 avec offset
```python import struct
temp_celsius = 24.50 temp_raw = int((temp_celsius + 40) * 100) # Offset +40°C
(24.50 + 40) * 100 = 6450¶
payload = struct.pack('>H', temp_raw) # big-endian unsigned short print(f"Temp 24.50°C -> bytes: {payload.hex()}") # 193a ```bash
Struct.pack format¶
| Format | Type | Bytes | Range |
|---|---|---|---|
B |
uint8 | 1 | 0-255 |
b |
int8 | 1 | -128 to 127 |
H |
uint16 | 2 | 0-65535 |
h |
int16 | 2 | -32768 to 32767 |
I |
uint32 | 4 | 0-4294967295 |
i |
int32 | 4 | -2147483648 to 2147483647 |
f |
float | 4 | IEEE 754 |
d |
double | 8 | IEEE 754 |
Prefix : > = big-endian, < = little-endian
ExploreIOT : Struct.pack multi-champs¶
Payload LoRaWAN : température (uint16) + humidité (uint16)
```python import struct
temperature = 24.50 humidity = 65.0
temp_raw = int(temperature * 100) # 2450 humidity_raw = int(humidity * 10) # 650
'>HH' = big-endian, 2 × uint16¶
payload = struct.pack('>HH', temp_raw, humidity_raw) print(f"Payload hex: {payload.hex()}") # 09b202 + 8a print(f"Payload bytes: {len(payload)} octets") # 4
Décodage¶
t, h = struct.unpack('>HH', payload) print(f"Temp: {t/100}°C, Humidity: {h/10}%") # 24.5°C, 65.0% ```json
Byte order (little vs big)¶
Big-endian (network byte order) :
text
0x1234 → [0x12, 0x34] (high byte first)python
Little-endian :
text
0x1234 → [0x34, 0x12] (low byte first)text
```python import struct
value = 0x1234 # 4660
big = struct.pack('>H', value) # big-endian print(f"Big-endian: {big.hex()}") # 1234
little = struct.pack('<H', value) # little-endian print(f"Little-endian: {little.hex()}") # 3412 ```json
Floating point : IEEE 754¶
Float (4 bytes) : ~7 chiffres significatifs
```python import struct
temp = 24.50 payload_float = struct.pack('>f', temp) print(f"Float: {payload_float.hex()}") # 41c40000
Décoder¶
unpacked = struct.unpack('>f', payload_float)[0] print(f"Unpacked: {unpacked}") # 24.5 ```json
Double (8 bytes) : ~15 chiffres significatifs
En IoT : Floats pour capteurs, mais peu courant (consomme de la bande).
Overflow vs underflow¶
Overflow : Valeur trop grande
python
import struct
try:
struct.pack('>H', 70000) # uint16 max = 65535
except struct.error as e:
print(f"Error: {e}") # unsigned short format requires 0 <= number <= 65535bash
Underflow : Valeur trop petite (négatif pour unsigned)
python
import struct
try:
struct.pack('>H', -5) # uint16 ne supporte pas les négatifs
except struct.error as e:
print(f"Error: {e}") # unsigned short format requires 0 <= number <= 65535bash
Bits individuels (bitwise)¶
Parfois, on doit packer plusieurs petites valeurs dans 1 byte.
```python
Flags : 3 bits + 5 bits dans 1 byte¶
status = 3 # 2 bits config = 5 # 5 bits
value = (status << 5) | config print(f"Packed: {bin(value)}") # 0b1011101 = 93
Unpack¶
status_unpacked = (value >> 5) & 0b11 config_unpacked = value & 0b11111 print(f"Status: {status_unpacked}, Config: {config_unpacked}") ```python
Points clés à retenir¶
- Octet = 8 bits, unité de base en IoT
- uint16 = 2 octets, 0-65535 : format classique LoRaWAN
- int16 = 2 octets signés : pour températures négatives
- struct.pack('>HH', x, y) = 4 octets (2 × uint16)
- Overflow = crashe ou wraparound silencieux
- Big-endian = ordre réseau LoRaWAN
- Floats = rares en IoT (bande limitée)
Appliquer dans ExploreIOT
struct.pack('>HH', temp, hum)produit exactement 4 octets (2 × unsigned short)- Chaque mesure capteur est encodée en mots de 16 bits (2 octets par valeur)
- Voir le journal — Encodage LoRaWAN pour le code concret