Skip to content

feat(bq27441): Add battery pet (tamagotchi) example with OLED.#399

Merged
nedseb merged 14 commits intomainfrom
feat/tamagotchie
Apr 16, 2026
Merged

feat(bq27441): Add battery pet (tamagotchi) example with OLED.#399
nedseb merged 14 commits intomainfrom
feat/tamagotchie

Conversation

@DumontALINE
Copy link
Copy Markdown
Contributor

@DumontALINE DumontALINE commented Apr 16, 2026

Closes #336

Summary

Add an interactive Tamagotchi-style example that combines four STeaMi peripherals: the BQ27441 battery gauge, the SSD1327 128×128 OLED display, the MCP23009E D-PAD, and the PWM buzzer.

The creature ages based on the real battery percentage and periodically requests the player to feed it or play with it via the D-PAD.

Game mechanics

Charge range Life stage Sprite scale
100 % – 70 % Child
70 % – 40 % Teenager
40 % – 10 % Adult
Below 10 % Dead (game over)

Every ~7 seconds, the Tamagotchi expresses a random need ("I'm bored" or "I'm hungry"). The player has a 5-second window to select the matching action (play / food) with UP/DOWN and confirm with LEFT. A correct answer triggers a happy sprite + success sound; a wrong or missed answer triggers an angry sprite + fail sound.

Drivers used

  • bq27441 — reads state_of_charge() to drive the aging system
  • ssd1327 — draws pixel-art sprites and text on the OLED
  • mcp23009e — reads the D-PAD buttons (UP / DOWN / LEFT / RIGHT)
  • pyb.Timer — drives the PWM buzzer for sound effects (start, hungry, bored, success, fail, evolution)

Test plan

  • Flash the firmware and run: make run SCRIPT=lib/bq27441/examples/tamagotchi.py
  • Verify the creature appears on the OLED with the correct sprite scale for the current battery level
  • Verify a need message appears after ~1 second of idle display
  • Press UP / DOWN to navigate the action menu, confirm with LEFT
  • Verify correct action → happy sprite + success sound, wrong action → angry sprite + fail sound
  • Verify timeout (no input for 5 s) → angry sprite + fail sound
  • Verify game over screen when battery drops below 10 %
  • Verify buzzer is silenced after exiting (Ctrl+C) thanks to the finally block

@DumontALINE DumontALINE force-pushed the feat/tamagotchie branch 2 times, most recently from fefdbe5 to 5cea1ab Compare April 16, 2026 08:31
@DumontALINE DumontALINE changed the title Feat/tamagotchie Feat(bq27441): Add battery pet (tamagotchi) example with OLED. Apr 16, 2026
@DumontALINE DumontALINE changed the title Feat(bq27441): Add battery pet (tamagotchi) example with OLED. feat(bq27441): Add battery pet (tamagotchi) example with OLED. Apr 16, 2026
@nedseb nedseb requested a review from Copilot April 16, 2026 09:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new bq27441 example demonstrating an OLED “battery pet” (tamagotchi-style) UI driven by fuel-gauge state-of-charge, using the board D-PAD (via MCP23009E) and buzzer for interaction.

Changes:

  • New MicroPython example tamagotchie.py integrating BQ27441 + SSD1327 OLED + MCP23009E D-PAD + buzzer PWM.
  • Implements sprite rendering, a simple “need/action” input loop, and basic success/fail sounds.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/bq27441/examples/tamagotchie.py Outdated
Comment on lines +183 to +194
def draw_character(cx, cy, scale, sprite):
"""Draw caractere"""
fb = display.framebuf
for y, row in enumerate(sprite):
for x, color in enumerate(row):
for dy in range(scale):
for dx in range(scale):
fb.pixel(cx + x*scale + dx, cy + y*scale + dy, color)


def creat_screen(selected_index, need, sprite, charge):
"""displays the screen"""
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several identifiers and docstrings have spelling/typo issues (creat_screen, creat_game_over_screen, soud_effect, and "Draw caractere"), which makes the example harder to follow and search for. Renaming these to correctly spelled, consistent snake_case names will improve maintainability (and also avoids introducing misspelled APIs if this code is reused).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correction in commit f94b3d9

Comment thread lib/bq27441/examples/tamagotchie.py Outdated
Comment on lines +240 to +283
def soud_effect(name):
sound = {
"start": [
(523, 120),
(659, 120),
(784, 120),
(1047, 400),
],

"hungry": [
(400, 150),
(350, 150),
(300, 300),
],

"bored": [
(500, 120),
(650, 120),
(800, 200),
],

"success": [
(600, 100),
(800, 100),
(1000, 200),
],

"evolution": [
(600, 120),
(750, 120),
(900, 120),
(1100, 150),
(1300, 300),
],

"fail": [
(500, 150),
(400, 150),
(300, 400),
]
}
melody = sound[name]
for freq, duration_ms in melody:
buzzer_tim.freq(freq)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

soud_effect() rebuilds the entire sound dictionary on every call, which creates a lot of allocations on MicroPython (and can increase GC pressure/fragmentation during gameplay). Move the melody table to a module-level constant and have soud_effect() only look up and play the selected melody.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correction in commit f94b3d9

Comment thread lib/bq27441/examples/tamagotchie.py Outdated
Comment on lines +297 to +346
while is_alive:
selected_index = 0
charge = fg.state_of_charge()

need = " "
creat_screen(selected_index, need, SPRITE_BASE, charge)
sleep_ms(1000)

need = random.choice(NEED)
if need == "I'm bored" :
sprite = SPRITE_SAD
soud_effect("bored")
else :
sprite = SPRITE_HUNGRY
soud_effect("hungry")

creat_screen(selected_index, need, sprite, charge)

start = ticks_ms()
win = None

while True:
timer = ticks_diff(ticks_ms(), start)
if timer >= 5000:
break


button = wait_for_button()
if button == "UP":
selected_index = (selected_index - 1)% len(ACTION)
creat_screen(selected_index, need, sprite, charge)
elif button == "DOWN":
selected_index = (selected_index + 1) % len(ACTION)
creat_screen(selected_index, need, sprite, charge)
elif button == "LEFT":
win = action_check(selected_index, need, win)
break
sleep_ms(20)

if win:
creat_screen(selected_index, need, SPRITE_HAPPY, charge)
soud_effect("success")
else:
creat_screen(selected_index, need, SPRITE_HANGRY, charge)
soud_effect("fail")
sleep_ms(1000)

if charge < 10:
is_alive = False
creat_game_over_screen()
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider wrapping the main loop in try/finally to ensure the buzzer is silenced (pulse_width_percent(0)) on exceptions/KeyboardInterrupt. Without a cleanup path, an interrupt during a tone can leave PWM running until reset.

Suggested change
while is_alive:
selected_index = 0
charge = fg.state_of_charge()
need = " "
creat_screen(selected_index, need, SPRITE_BASE, charge)
sleep_ms(1000)
need = random.choice(NEED)
if need == "I'm bored" :
sprite = SPRITE_SAD
soud_effect("bored")
else :
sprite = SPRITE_HUNGRY
soud_effect("hungry")
creat_screen(selected_index, need, sprite, charge)
start = ticks_ms()
win = None
while True:
timer = ticks_diff(ticks_ms(), start)
if timer >= 5000:
break
button = wait_for_button()
if button == "UP":
selected_index = (selected_index - 1)% len(ACTION)
creat_screen(selected_index, need, sprite, charge)
elif button == "DOWN":
selected_index = (selected_index + 1) % len(ACTION)
creat_screen(selected_index, need, sprite, charge)
elif button == "LEFT":
win = action_check(selected_index, need, win)
break
sleep_ms(20)
if win:
creat_screen(selected_index, need, SPRITE_HAPPY, charge)
soud_effect("success")
else:
creat_screen(selected_index, need, SPRITE_HANGRY, charge)
soud_effect("fail")
sleep_ms(1000)
if charge < 10:
is_alive = False
creat_game_over_screen()
try:
while is_alive:
selected_index = 0
charge = fg.state_of_charge()
need = " "
creat_screen(selected_index, need, SPRITE_BASE, charge)
sleep_ms(1000)
need = random.choice(NEED)
if need == "I'm bored" :
sprite = SPRITE_SAD
soud_effect("bored")
else :
sprite = SPRITE_HUNGRY
soud_effect("hungry")
creat_screen(selected_index, need, sprite, charge)
start = ticks_ms()
win = None
while True:
timer = ticks_diff(ticks_ms(), start)
if timer >= 5000:
break
button = wait_for_button()
if button == "UP":
selected_index = (selected_index - 1)% len(ACTION)
creat_screen(selected_index, need, sprite, charge)
elif button == "DOWN":
selected_index = (selected_index + 1) % len(ACTION)
creat_screen(selected_index, need, sprite, charge)
elif button == "LEFT":
win = action_check(selected_index, need, win)
break
sleep_ms(20)
if win:
creat_screen(selected_index, need, SPRITE_HAPPY, charge)
soud_effect("success")
else:
creat_screen(selected_index, need, SPRITE_HANGRY, charge)
soud_effect("fail")
sleep_ms(1000)
if charge < 10:
is_alive = False
creat_game_over_screen()
finally:
buzzer_ch.pulse_width_percent(0)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correction in commit f94b3d9

Comment thread lib/bq27441/examples/tamagotchie.py Outdated
Comment on lines +301 to +313
need = " "
creat_screen(selected_index, need, SPRITE_BASE, charge)
sleep_ms(1000)

need = random.choice(NEED)
if need == "I'm bored" :
sprite = SPRITE_SAD
soud_effect("bored")
else :
sprite = SPRITE_HUNGRY
soud_effect("hungry")

creat_screen(selected_index, need, sprite, charge)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gameplay timing and “aging” behavior described in the PR don’t match the current loop: requests are not generated every 2 seconds (there’s a 1s idle + up to 5s wait + 1s result), and the charge-based child/teen/adult stages aren’t represented beyond a sprite scale change. Either update the implementation to match the described behavior, or adjust the PR description to reflect what the example actually does.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modification made in the description of the pr

Comment thread lib/bq27441/examples/tamagotchie.py Outdated
Comment on lines +59 to +73
[ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0],
[ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0],
[ 0,15,15,15,15,15,15,15,15,15,15,15, 0],
[ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0],
[ 0,15, 0, 0,15, 0, 0, 0,15, 0, 0,15, 0],
[15, 0, 0, 0, 0,15,15,15, 0, 0, 0, 0,15],
[15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15],
[ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0],
[15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0],
[ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0],
[ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0],
[ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0],
[ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0],
[ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0],
[ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0],
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file will fail ruff check due to many formatting violations in the sprite arrays (e.g., missing whitespace after commas like 0,15 and inconsistent spacing inside brackets). Running ruff format (or reformatting the sprite lists to use standard spacing) will avoid hundreds of E231/E201-style lint errors in CI.

Suggested change
[ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0],
[ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0],
[ 0,15,15,15,15,15,15,15,15,15,15,15, 0],
[ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0],
[ 0,15, 0, 0,15, 0, 0, 0,15, 0, 0,15, 0],
[15, 0, 0, 0, 0,15,15,15, 0, 0, 0, 0,15],
[15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15],
[ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0],
[15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0],
[ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0],
[ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0],
[ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0],
[ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0],
[ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0],
[ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0],
[0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0],
[0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 0],
[0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0],
[0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0],
[0, 15, 0, 0, 15, 0, 0, 0, 15, 0, 0, 15, 0],
[15, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 15],
[15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15],
[0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0],
[15, 0, 0, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0],
[0, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0],
[0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0],
[0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0],
[0, 0, 0, 15, 0, 15, 15, 15, 0, 15, 0, 0, 0],
[0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0],
[0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 0],

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

@DumontALINE DumontALINE Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correction in commit d2060a4

Comment thread lib/bq27441/examples/tamagotchie.py Outdated

# sound
buzzer_tim = Timer(1, freq=1000)
buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER"))
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buzzer_ch = ... uses multiple spaces before =, which is flagged by ruff (E221). Please normalize to single spaces so make lint passes.

Suggested change
buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER"))
buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER"))

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correction in commit f85e843

Comment thread lib/bq27441/examples/tamagotchie.py Outdated
Comment on lines +196 to +197
display.text(need, 25, 20)
display.text(str(charge), 50, 10)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

display.text() is called without an explicit color here, so it will use the FrameBuffer default (usually 1), which is nearly black on a GS4 (0–15) OLED and can make the text effectively invisible. Pass an explicit bright color (consistent with the menu text using 15).

Suggested change
display.text(need, 25, 20)
display.text(str(charge), 50, 10)
display.text(need, 25, 20, 15)
display.text(str(charge), 50, 10, 15)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correction in commit f85e843

Comment thread lib/bq27441/examples/tamagotchie.py Outdated
Comment on lines +199 to +207
if charge > 70 :
scale = 1
x = 55
y = 60
elif charge < 70 and charge > 40 :
scale = 2
x = 45
y = 50
else :
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Battery threshold logic has both style and correctness issues: whitespace before : will fail ruff (E203), and the comparisons exclude boundary values (e.g. charge == 70 falls into the else branch). Consider using inclusive ranges (and chained comparisons) so the stage mapping matches the documented 100–70 / 70–40 / 40–10 / <10 behavior.

Suggested change
if charge > 70 :
scale = 1
x = 55
y = 60
elif charge < 70 and charge > 40 :
scale = 2
x = 45
y = 50
else :
if charge >= 70:
scale = 1
x = 55
y = 60
elif 40 <= charge < 70:
scale = 2
x = 45
y = 50
else:

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correction in commit a74e54b

Comment thread lib/bq27441/examples/tamagotchie.py Fixed
@nedseb nedseb self-requested a review April 16, 2026 13:46
@nedseb nedseb added the enhancement New feature or request label Apr 16, 2026
Copy link
Copy Markdown
Contributor

@nedseb nedseb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aline,

bravo pour cette première PR ! Le jeu fonctionne et c'est un très bon exemple d'intégration de plusieurs composants de la carte STeaMi (batterie, écran OLED, D-PAD, buzzer). Les sprites sont sympas et la mécanique de jeu (besoin aléatoire, fenêtre de réponse, vieillissement) est bien pensée.

Je liste quelques suggestions classées par importance. Rien de bloquant — c'est surtout des ajustements de convention et de lisibilité.


1. Typo dans le nom de fichier

tamagotchie.pytamagotchi.py

L'orthographe anglaise (et japonaise d'origine) est "Tamagotchi" sans le e final. C'est ce nom qui sera visible pour tous les utilisateurs du projet, donc autant partir sur la bonne orthographe.

git mv lib/bq27441/examples/tamagotchie.py lib/bq27441/examples/tamagotchi.py

2. Casse incohérente dans NEED

NEED = ["I'm bored", "i'm hungry"]
#        ^            ^
#    majuscule         minuscule

Les deux chaînes sont affichées sur l'écran OLED et comparées dans action_check. Harmonise la casse — en mettant une majuscule aux deux par exemple :

NEED = ["I'm bored", "I'm hungry"]

Et pense à mettre à jour la comparaison dans action_check en conséquence.

3. Simplification de action_check

La fonction actuelle est un peu plus complexe qu'elle ne doit l'être :

def action_check(selected_index, need, win):
    name = ACTION[selected_index]
    if need == "I'm bored" and name == "play":
        win = True
        return win
    if need == "i'm hungry" and name == "food":
        win = True
        return win
    else:
        win = False
        return win

Le paramètre win n'est jamais lu — il est toujours écrasé avant d'être retourné. La fonction peut simplement retourner un booléen :

def action_check(selected_index, need):
    """Check if the selected action matches the current need."""
    name = ACTION[selected_index]
    if need == "I'm bored" and name == "play":
        return True
    if need == "I'm hungry" and name == "food":
        return True
    return False

C'est plus court, plus lisible, et il n'y a plus de paramètre inutilisé. L'appel dans main() devient simplement win = action_check(selected_index, need).

(Conseil général : si une variable en paramètre est toujours écrasée avant d'être lue dans la fonction, elle ne devrait pas être un paramètre — c'est une valeur de retour.)

4. Espaces avant les : (else :else:)

À quelques endroits dans le code, il y a un espace superflu avant les deux-points :

if need == "I'm bored" :     # ← espace en trop
    ...
else :                        # ← espace en trop

La convention Python (et le style du projet) est de coller le : : if ...:, else:. Ruff ne les signale pas en mode preview, mais c'est un standard PEP 8 important (E203/E275).

5. Son "evolution" défini mais jamais joué

Le dictionnaire SOUND contient une mélodie "evolution" qui n'est appelée nulle part dans le code. Deux options :

  • Si elle est prévue : l'ajouter quand le tamagotchi passe d'un stade à l'autre (child → teenager → adult). Ce serait un super feedback pour le joueur.
  • Si elle n'est plus nécessaire : la retirer pour garder le code propre.

6. Constantes magiques

Quelques nombres dans main() gagneraient à être nommés pour la lisibilité :

IDLE_DISPLAY_MS = 1000
RESPONSE_TIMEOUT_MS = 5000
RESULT_DISPLAY_MS = 1000

Ce n'est pas obligatoire pour un fichier d'exemple, mais ça aide à comprendre la mécanique du jeu d'un coup d'œil.

7. Commentaires de section

Les séparateurs de type :

# -----------SCREEN-----------
# -----------gameplay-----------
# -----------main-----------

fonctionnent, mais un style plus idiomatique en Python serait :

# --- Screen helpers ---
# --- Gameplay logic ---
# --- Main loop ---

C'est d'ailleurs le style utilisé dans le Makefile du projet (# --- Linting ---, # --- Testing ---).


Récapitulatif

Point Priorité
Renommer tamagotchie.pytamagotchi.py Haute (typo visible)
Harmoniser la casse de NEED Haute (bug potentiel si tu changes les comparaisons)
Simplifier action_check (retirer le paramètre win inutile) Moyenne
Retirer les espaces avant : Faible (style)
Jouer ou retirer le son "evolution" Faible
Nommer les constantes magiques Optionnel
Style des commentaires de section Optionnel

Les 3 premiers points sont ceux que je te suggère de traiter. Le reste peut venir après si tu le souhaites. N'hésite pas à poser des questions si une suggestion n'est pas claire !

nedseb added a commit that referenced this pull request Apr 16, 2026
Closes #400.

These three pycodestyle rules are in preview in ruff 0.11.6 and were not
active because of explicit-preview-rules = true. Add them to the explicit
select list and auto-fix the 11 existing violations across the codebase:

  E203 — whitespace before ':' (catches `else :`, `if x :`, etc.)
  E302 — expected 2 blank lines before function/class definition
  E303 — too many blank lines inside a block

E203 was spotted in PR #399 (Aline's tamagotchi example) and E302/E303
in PR #376 (Kaan's spirit level) — both were caught manually because
ruff did not flag them.
nedseb added a commit that referenced this pull request Apr 16, 2026
* tooling: Enable ruff preview rules E203, E302, and E303.

Closes #400.

These three pycodestyle rules are in preview in ruff 0.11.6 and were not
active because of explicit-preview-rules = true. Add them to the explicit
select list and auto-fix the 11 existing violations across the codebase:

  E203 — whitespace before ':' (catches `else :`, `if x :`, etc.)
  E302 — expected 2 blank lines before function/class definition
  E303 — too many blank lines inside a block

E203 was spotted in PR #399 (Aline's tamagotchi example) and E302/E303
in PR #376 (Kaan's spirit level) — both were caught manually because
ruff did not flag them.

* tooling: Add steami_screen to Pylance extraPaths.

* tooling: Remove deprecated and unknown settings from VSCode config.

* tooling: Migrate Pylance settings from VSCode to pyproject.toml.

Pylance ignores python.analysis.* in settings.json when a pyproject.toml
exists and warns "cannot be set when a pyproject.toml is being used".

Move typeCheckingMode, extraPaths, stubPath, and diagnosticSeverityOverrides
into [tool.pyright] in pyproject.toml where Pylance reads them. This also
makes the configuration IDE-agnostic (works for any pyright-based tool,
not just VSCode).
nedseb added a commit that referenced this pull request Apr 16, 2026
Address review comments from #399:

1. Rename tamagotchie.py -> tamagotchi.py (fix English spelling).

2. Harmonize NEED casing: "i'm hungry" -> "I'm hungry" and update
   the matching logic in action_check accordingly.

3. Simplify action_check: remove the unused `win` parameter (it was
   always overwritten before being read) and return a boolean directly.

4. Remove unused "evolution" sound (defined but never played).

5. Rename SPRITE_HANGRY -> SPRITE_ANGRY (standard English).

6. Fix all style issues: spaces before colons (E203), inconsistent
   SOUND dict indentation, missing blank lines before functions (E302),
   missing operator spacing in draw_character (E225), double blank lines
   inside blocks (E303).

7. Add docstrings to all functions and a module-level docstring.

8. Name magic timing constants: IDLE_DISPLAY_MS, RESPONSE_TIMEOUT_MS,
   RESULT_DISPLAY_MS.

9. Add phase comments in main() for readability (idle / need / response /
   result).
DumontALINE and others added 14 commits April 16, 2026 22:13
Address review comments from #399:

1. Rename tamagotchie.py -> tamagotchi.py (fix English spelling).

2. Harmonize NEED casing: "i'm hungry" -> "I'm hungry" and update
   the matching logic in action_check accordingly.

3. Simplify action_check: remove the unused `win` parameter (it was
   always overwritten before being read) and return a boolean directly.

4. Remove unused "evolution" sound (defined but never played).

5. Rename SPRITE_HANGRY -> SPRITE_ANGRY (standard English).

6. Fix all style issues: spaces before colons (E203), inconsistent
   SOUND dict indentation, missing blank lines before functions (E302),
   missing operator spacing in draw_character (E225), double blank lines
   inside blocks (E303).

7. Add docstrings to all functions and a module-level docstring.

8. Name magic timing constants: IDLE_DISPLAY_MS, RESPONSE_TIMEOUT_MS,
   RESULT_DISPLAY_MS.

9. Add phase comments in main() for readability (idle / need / response /
   result).
@nedseb nedseb force-pushed the feat/tamagotchie branch from 697c2fa to e362948 Compare April 16, 2026 20:13
Copy link
Copy Markdown
Contributor

@nedseb nedseb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aline, j'ai poussé un commit de corrections (e362948) qui reprend les points de ma review initiale et ceux de Copilot. Voici le détail :

1. Renommage tamagotchie.pytamagotchi.py — l'orthographe anglaise/japonaise est "Tamagotchi" sans le e final.

2. Casse harmonisée dans NEED"i'm hungry""I'm hungry" (majuscule comme "I'm bored"). La comparaison dans action_check a été mise à jour.

3. action_check simplifiée — le paramètre win (toujours écrasé, jamais lu) a été retiré. La fonction retourne directement un booléen avec une expression simple.

4. Son "evolution" retiré — il était défini mais jamais joué. S'il est prévu pour plus tard, on pourra le remettre quand le mécanisme d'évolution sera implémenté.

5. SPRITE_HANGRYSPRITE_ANGRY — "hangry" est du slang, "angry" est le mot standard.

6. Style — espaces avant : (E203), indentation du dict SOUND, lignes vides manquantes avant les fonctions (E302), espaces manquants autour des opérateurs dans draw_character (E225), double ligne vide dans le bloc while (E303). Tout corrigé, make lint passe.

7. Constantes nomméesIDLE_DISPLAY_MS = 1000, RESPONSE_TIMEOUT_MS = 5000, RESULT_DISPLAY_MS = 1000 remplacent les nombres magiques.

8. Docstrings et commentaires — ajoutés sur toutes les fonctions et les phases du jeu dans main().

Branche rebasée sur main. Prêt à merger.

@nedseb nedseb merged commit 190354f into main Apr 16, 2026
9 checks passed
@nedseb nedseb deleted the feat/tamagotchie branch April 16, 2026 20:16
semantic-release-updater Bot pushed a commit that referenced this pull request Apr 16, 2026
# [0.23.0](v0.22.0...v0.23.0) (2026-04-16)

### Features

* **bq27441:** Add battery pet (tamagotchi) example with OLED. ([#399](#399)) ([190354f](190354f))
@semantic-release-updater
Copy link
Copy Markdown

🎉 This PR is included in version 0.23.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(bq27441): Add battery pet (tamagotchi) example with OLED.

3 participants