Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

RFID-controlled musicplayer powered by ESP32

License

NotificationsYou must be signed in to change notification settings

biologist79/ESPuino

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

build workflow

Forum

  • EN: I've set up a primarily German-speaking community with much documentation. Also aninternational corner for non-German-speakers is available athttps://forum.espuino.de.GitHub login can be used for signing in there (optional).
  • DE: Ich habe ein primär deutschsprachiges Forum aufgesetzt, welches ich mit reichlich Dokuversehen habe. Würde mich freuen, euch dort zu sehen:https://forum.espuino.de. Ihr könnt euchdort mit eurem Github-Login einloggen, jedoch auch "normal" anmelden. Dokumentation findet ihrinsbesondere hier:https://forum.espuino.de/c/dokumentation/anleitungen/10.

News

⚠️ By the end of october 2023, ESPuino switched framework from ESP32-Arduino1 to ESP32-Arduino2.This brought lots of improvements but as it turned out, due to memory restrictions this versionno longer runs safely on ESP32 without PSRAM. So please make sure to use an ESP32-WROVER!

Current development

There is adevelopment branch (dev) that containsnew features, that will be introduced and tested there first until they become part of the masterbranch. Feel free to try but be advised this could be unstable.

ESPuino - what's that?

The basic idea of ESPuino is to use RFID tags to control an audio player. Even for kids this conceptis simple: place a RFID-tagged object (card, toy character, etc.) on top of a box and the musicstarts to play stuff from SD card or webradio. Place a different RFID tag on it and something elseis played. Simple as that.

This project is based on the popular microcontrollerESP32 byEspressif. Why? It's powerful andhaving WiFi support out-of-the-box enables further features like an integrated webserver,smarthome-integration via MQTT, webradio and FTP server. And even Bluetooth, too! However, myprimary focus was to port the project to a modular base: MP3-decoding is done in software and thedigital music output is done via the popularI2S protocol.So we need aDAC to make an analogsignal of it: I did all my tests withMAX98357A,UDA1334,MS6324 andPCM5102a.General advice: ESPuino makes use of libraryESP32-audioI2S; so everything that's supposed towork with this library should work with ESPuino, too (but maybe not right out-of-the-box).Especially this is true forES8388.

Hardware setup

You could start on a breadboard with jumper wires but Istrongly recommend to start right awaywith a PCB that was especially developed for ESPuino. There are several available, butESPuino-mini 4L (SMD) can be considered asbeing the latest generation. Furthermore you need a ESP32-develboard like (or another one that'spin compatible):

⚠️Due to memory restrictions meanwhile it's mandatory to use ESP32 withPSRAM. This being said you need to make sure that your develboard carries an ESP32-WROVER.And you should make sure that 16 MB flash memory is available (both is true for alldevelboards named above).

Optionally aheadphone-pcbcan be attached toESPuino-mini 4L (SMD).

However, feel free to develop PCBs yourself. But again, be advised your ESP32 needs PSRAM in order torun ESPuino properly.

Getting started

  • Much more documentation in germanlanguage.
  • You need to install Microsoft'sVisual Studio Code.
  • InstallPlatformIO Plugin intoVisual StudioCode and make sure to have a look at thedocumentation.Step-by-step-manual is availablehere
  • InstallGit and make a copy ("clone") of my repository to your localcomputer usinggit clone https://github.com/biologist79/ESPuino.git. Using Git you can keep yourlocal repository easily up to date without doing copy'n'paste. To keep it up to date rungit pull origin master. Further infoshereandhere.
  • (Optional) InstallGitLensas plugin (to have advanced Git features in VSCode).
  • Now, that the Git repository is saved locally, import this folder into Platformio as a project.
  • Select thedesiredenvironment (e.g.lolin_d32_pro_sdmmc_pe).
  • Editsrc/settings.h according your needs.
  • Edit board-specific (HAL) config-file (e.g.settings-lolin_d32_pro_sdmmc_pe.h for LolinD32/D32 pro). If you're running a board that is not listed there: start withsettings-custom.hand change it according your needs.
  • Connect your develboard via USB, click the alien-head icon in the left sidebar, choose the projecttask that matches your desired HAL and runUpload and Monitor. All libraries necessary arefetched automatically and compilation of the code gets started. After that, your ESP32 is flashedwith the firmware. Depending on your develboard it might be necessary to push a button in order toallow ESP32 to enter flash mode (not necessary für Lolin32, D32 und D32 pro).
  • Now have a look at the serial output at the bottom of Visual Studio Code's window. At the firstrun there might appear a few error messages (related to missing entries in NVS). Don't worry, thisis just normal. However, make sure the SD card is detected as this is mandatory!
  • If everything ran fine, at the first run, ESPuino should open an access-point and ESPuino offers acaptive portal that is shown on your computer. If that's not the case, join a WiFi called"ESPuino" and enterhttp://192.168.4.1 to your webbrowser. Enter WiFi credentials and thehostname there (or in the captive portal). After saving the configuration, restart ESPuino.
  • After reboot ESPuino tries to join your WiFi (with the credentials previously entered). If thatwas successful, an IP is shown in the serial console. You can access ESPuino's GUI using awebbrowser via this IP; make sure to allow Javascript. If the mDNS feature is active insrc/settings.h, you can use the hostname configured extended by .local instead the IP. So if youconfiguredespuino as hostname, you can usehttp://espuino.local for web GUI and FTP.
  • Via FTP and web GUI you can upload data (expect a throughput like 320 kB/s up to 700 kB/s).
  • FTP needs to be activated after boot if you need it! Don't forget to assign actionENABLE_FTP_SERVER insettings.h to be able to activate it. Neopixel flashes green (1x) ifenabling was successful. It'll be disabled automatically after next reboot. Means: you have toenable it every time you need it (if reboot was in between). Sounds annoying and maybe it is,but's running this way in order to have more heap-memory available (for webstream) if FTP isn'tneeded.
  • Via webbrowser you can configure various settings and pair RFID tags with actions. IfMQTT/FTP-support was not compiled, their config tabs won't appear.

SD-card: SPI or SD-MMC (1 bit)-mode?

Having the SD card working is mandatory, ESPuino doesn't start without working SD card (at leastunlessNO_SDCARD hasn't been enabled previously). However, there are two modes available tointerface SD cards: SPI and SDMMC (1 bit). Be advised that SDMMC is twice as fast as SPI andneeds one GPIO less. So basically it's a no-brainer.

Which RFID-reader: RC522 or PN5180?

RC522 is so to say the ESPuino standard. It's cheap and works, but RFID tags have to be placed closeto the reader. PN5180 instead has better RFID range/sensitivity and can read ISO-15693 / iCodeSLIX2-tags aka 'Tonies' (you need a password to read Tonies), too. You can also wake up ESPuino withthe a RFID tag (after flashing PN5180 with a new firmware). This feature is called LPCD.Disadvantages PN5180: it's more expensive and needs more GPIOs (6/7 instead of 4). In my opinionit's worth it! Refer to PN5180's wiring section below for further information. Hint: if using 3.3 Vonly make sure to connect these 3.3 V to PN5180's 5 V AND 3.3 V. Sounds weird but it's necessary.

3.3 V or 5 V?

ESP32 runs at 3.3 V only. But what about the periphery?

  • 3.3 V! Because: if you plan to use battery mode with LiPo/LiFePO4, there's no 5 V available (unlessUSB is connected or you make use of a boost converter). That's why my focus is on 3.3 V only. Ifyou want to use 5 V instead - do so, but be advised it might not be compatible with battery mode.
  • MAX98357A: provides more power at 5 V but also runs at 3.3 V. Anyway: it's still loud enough (inmy opinion).
  • Neopixel: specification says it needs 5 V but runs at 3.3 V as well.
  • RC522: needs 3.3 V (don't ever power with 5 V!)
  • PN5180: at 3.3 V make sure to connect both 5 V and 3.3 V pins to 3.3 V. If 5 V is available allthe time: connect 5 V to 5 V and 3.3 V to 3.3 V.
  • SD card: needs 3.3 V but if voltage regulator is onboard, it can be connected to 5 V as well
  • Rotary encoder: 3.3 V (don't power with 5 V! Encoder doesn't care if connected to 3.3 or 5 V, butGPIOs of ESP32 do!)

WiFi

WiFi is mandatory for web GUI, FTP, MQTT and webradio. However, WiFi can be temporarily orpermanently disabled (and ESPuino remembers this state after the next restart). There are two waysto (re-)enable/disable WiFi:

  • Use a specialmodification card thatcan be configured via web GUI.
  • Assign actionCMD_TOGGLE_WIFI_STATUS to a button (or multi-button). This toggles the currentWiFi status.

Bluetooth

⚠️Due to memory restrictions it's not possible to run Bluetooth inparallel with WiFi. This means that you cannot stream webradio via Bluetoothor access the web GUI while this mode is enabled.

ESPuino as A2DP sink (stream to ESPuino)

ESPuino can be used as Bluetooth sink (A2DP sink). In this mode you can stream audio (e.g. from amobile device) via Bluetooth to your ESPuino. This mode can be enabled/disabled via a RFIDmodification card or by assigning actionCMD_TOGGLE_BLUETOOTH_MODE to a button (or multi-button).Applying this will restart ESPuino immediately. Activated Bluetooth is indicated by fourslow rotatingblue-violet LEDs. After the Bluetooth device is paired the LEDs turn to blue.

ESPuino as A2DP source (stream from ESPuino)

ESPuino can also be used to stream audio (A2DP source) to a Bluetooth headset or external Bluetoothspeakers. This mode can be enabled/disabled via a RFID modification card or by assigning actionCMD_TOGGLE_BLUETOOTH_SOURCE_MODE to a button (or multi-button). Applying this will restart ESPuinoimmediately. Activated Bluetooth is indicated by four slow rotatingblue-violet LEDs. After theBluetooth headset is connected LEDs turn to blue.

Port expander

There might be situations where you run out of GPIOs. To address this, a port expanderPCA9555 can be used to extend the number ofinput channels (output mode is only supported in special cases). PCA9555 provides 2 ports with 8channels each - so 16 channels in total. To activate PCA9555 you need to enablePORT_EXPANDER_ENABLE. Like GPIOs in your develboard-specific settings-file, you can assignnumbers. Range is100 (port 0 channel 0) ->115 (port 1 channel 7). ViaexpanderI2cAddress theport expander's I2C-address can be changed. It's0x20 if pinsA0,A1,A2 are wired to GND.

After ESPuino is connected to your WiFi

After making ESPuino part of your LAN/WiFi, the 'regular' web GUI is available at the IP assigned byyour router (or the configured hostname). Using this GUI you can:

  • configure WiFi
  • make bindings between RFID tag, file/directory/URL and playback mode
  • make bindings between RFID tag and a modification type
  • configure MQTT (if enabled)
  • configure FTP (if enabled)
  • configure initial volume, maximum volume (speaker / headphone), brightness of Neopixel (night mode/ default) and inactivity time
  • configure voltage levels for battery mode
  • view logs / status / current track
  • control player
  • run modifications (like modification card)
  • upload audiofiles (called web transfer)
  • do OTA updates (ESP32 with 16 MB of flash memory only)
  • import + delete NVS-RFID-assigments
  • restart + shutdown ESPuino

ℹ️ As you apply a RFID tag to the RFID reader, the corresponding ID is pushed tothe GUI automatically. So there's no need to enter such IDs manually (unless you want to). Thefile path is filled out automatically by selecting a file/directory in the file browser.

Interacting with ESPuino

Playback modes

It's not just simply playing music; different playback modes are supported:

  • Single track => plays one track one time
  • Single track (loop) => plays one track forever
  • Single track of a directory (random). Followed by sleep => picks and plays one single track outof a directory and falls asleep subsequently. Neopixel gets dimmed.
  • Audiobook=> single file or playlist/folder; last play position (file and playlist) is saved(when pushing pause or moving to another track) and reused next time
  • Audiobook (loop) => same as audiobook but loops forever
  • Folder/playlist (sorted) => plays all tracks in order from a folder one time
  • Folder/playlist (random order) => plays all tracks in random order from a folder one time
  • Folder/playlist (sorted) => plays all tracks in order from a folder forever
  • Folder/playlist (random order) => plays all tracks in random order from a folder forever
  • All tracks of a random subdirectory (sorted) => plays of tracks in order of arandomly picked subdirectory of a given directory
  • All tracks of a random subdirectory (random order) => plays all tracks in random order of arandomly picked subdirectory of a given directory
  • Webradio => always only one "track": plays a webstream
  • List (files from SD and/or webstreams) from local .m3u-File => can be one or more files /webradio stations with local .m3u as sourcefile

Modification RFID tags

There are special RFID tags, that don't start music by themselves but can modify things. If applieda second time, it's previous action/modification will be reversed.

So first make sure to start the music then use a modification card in order to apply your desiredmodification:

  • Lock/unlock all buttons
  • Sleep after 5/30/60/120 minutes
  • Sleep after end of current track
  • Sleep after end of playlist
  • Sleep after five tracks
  • Dim Neopixel
  • Loop track
  • Loop playlist
  • Toggle WiFi (enable/disable) => disabling WiFi while webstream is active will stop a runningwebstream instantly!
  • Toggle Bluetooth sink (enable/disable) => restarts ESPuino immediately. In this mode you canstream to your ESPuino via BT.
  • Toggle Bluetooth source (enable/disable) => restarts ESPuino immediately. In this mode yourESPuino can stream via BT to an external device.
  • Toggle through the different modes (Normal => BT-Sink => BT-Source => Normal)
  • Speech output of IP-address or current time

ℹ️ All sleep modes do dimming (Neopixel) automatically because it's supposed tobe used in the evening when going to bed. Well, at least that's my children's indication :-)

ℹ️ Track and playlist loop mode can both be activated at the same time, butunless track loop isn't deactivated, playlist loop won't be effective

Neopixel LEDs (optional)

Indicates different things. Don't forget configuration of number of LEDs via#define NUM_LEDS.Most designs use a Neopixel ring, but a linear strip is also possible.

ℹ️ Some Neopixels use a reversed addressing which leads to the 'problem', thatall effects are shown counter clockwise. If you want to change that behaviour, just enableNEOPIXEL_REVERSE_ROTATION.

Boot

  • While booting: every second LED (rotating orange)
  • Unable to mount SD: LEDs flashing red (will remain forever unless SD card is available orSHUTDOWN_IF_SD_BOOT_FAILS is active)

Status

  • Idle: four LEDs slowly rotating (white if WiFi connected; green if WiFi disabled or ESPuino isabout to connect to WiFi)
  • Bluetooth: four LEDs slow rotating coloured blue
  • Error: all LEDs flashing red (1x) if an action was not accepted
  • OK: all LEDs flashing green (1x) if an action was accepted
  • Power Off: red-circle that grows until long-press-time is reached
  • Buttons Locked: track-progress-LEDs coloured red

Playback

  • Busy: violet; four fast rotating LEDs when generating a playlist. Duration depends on thenumber of files in your playlist.
  • Track Progress: rainbow; number of LEDs relative to play-progress
  • Playlist Progress: blue; appears only shortly in playlist-mode with the beginning every newtrack; number of LEDs relative to progress
  • Webstream: two slow rotating LEDs that change their colours rainbow-wise as the streamproceeds
  • Volume: green => red-gradient; number of LEDs relative from current to max volume
  • Paused: track-progress-LEDs coloured orange
  • Rewind: if single-track-loop is activated a LED-rewind is performed when restarting the giventrack

Battery Status (optional)

  • Undervoltage: flashes three times red if battery-voltage is too low. This voltage-level can beconfigured via GUI.
  • Short press of rotary encoder's button provides battery-voltage visualisation via Neopixel. Upperund lower voltage cut-offs can be adjusted via GUI. So for example if lower voltage is set to 3.2V and upper voltage to 4.2 V, 50% of the LEDs indicate a voltage of 3.7 V.

Buttons

⚠️ This section describes my default-design: 3 buttons + rotary-encoder. Feel free tochange number of buttons (up to 5) and button-actions according your needs insettings.h andyour develboard-specific config-file (e.g.settings-lolin32.h). At maximum you can activate fivebuttons + rotary-encoder. Minimum duration for long press (to distinguish vom short press) in msis defined byintervalToLongPress. All actions available are listed insrc/values.h. If usingGPIO >= 34 make sure to add a external pullup-resistor (10 k).

  • Previous (short): previous track / beginning of the first track if pressed while first trackis playing
  • Previous (long): first track of playlist
  • Next (short): next track of playlist
  • Next (long): last track of playlist
  • Pause/Play (short/long): pause/play
  • Rotary Encoder (turning): vol +/-
  • Rotary Encoder (button long): switch off (only when on)
  • Rotary Encoder (button short): switch on (when switched off)
  • Rotary Encoder (button short): show battery-voltage via Neopixel (when switched on andMEASURE_BATTERY_VOLTAGE is active)
  • Previous (long; keep pressed) +Next (short) + release (both): toggle WiFienabled/disabled

Virtual RFID cards

Any of the button actions can also be assigned to virtual RFID cards.Those cards then can be assigned on the web GUI like normal cards.To select a virtual RFID card, just press the configured button action, the virtual RFID automatically gets filled in in the web GUI.

Music playback

  • Music starts to play right away after a valid RFID tag was applied (if it's known to ESPuino).
  • IfPLAY_LAST_RFID_AFTER_REBOOT is active, ESPuino will remember the last RFID applied =>music-autoplay.
  • If a folder should be played that contains many MP3s, the playlist generation can take a fewseconds.
  • A file's name including path isn't allowed to exceed 255 characters.
  • While the playlist is generated Neopixel indicates BUSY-mode.
  • After the last track was played, Neopixel indicates IDLE-mode.

Audiobook mode

This mode is different from the others because the last playback position is saved, when...

  • next track starts.
  • first/previous/last track requested by button.
  • pause was pressed.
  • track is over.
  • playlist is over (position is reset to the first track and file position 0).
  • As per default last playback position is not saved when applying a new RFID tag. You can enablethis usingSAVE_PLAYPOS_WHEN_RFID_CHANGE.
  • As per default last playback position is not saved when doing shutdown. You can enable this usingSAVE_PLAYPOS_BEFORE_SHUTDOWN.

FTP (optional)

  • FTP needs to be activated after boot! Don't forget to assign actionENABLE_FTP_SERVER insettings.h or use a modification card to activate it! Neopixel flashes green (1x) if enablingwas successful. It'll be disabled automatically after next reboot. Means: you have to enable itevery time you need it (if reboot was in between). Sounds annoying and maybe it is, but it'srunning this way in order to save heap memory when FTP isn't needed.
  • Why FTP? Well: in order to avoid exposing the SD card or disassembling ESPuino all the time foradding new music, it's possible to transfer music to the SD card using FTP. Another possibilityis to do via web GUI (webtransfer).
  • Default user and password are set toesp32 /esp32 but can be changed via GUI.
  • Secured FTP is not available. So make sure to disable SSL/TLS.
  • Software: my recommendation isFilezilla as it's free andavailable for multiple platforms.
  • Please note: if music is played in parallel, this rate decreases dramatically! So better stopplayback when doing file transfers.

Energy saving

As already described in the modifications section, there are different sleep modes available.Additionally the ESP32 controller will be put to deep sleep after 10 minutes of inactivity(configurable viamaxInactivityTime) unless ESPuino doesn't play music, has a FTP client connectedand any input via buttons. Every button interaction resets the counter.

Backups

As all assignments between RFID IDs and actions (playback mode, file to play, ...) is saved in ESP'sNVS, the problem is that it's all gone when the ESP is broken. So that's where a backup comes inhandy. Every time you change or add a new assignment between a RFID tag and an action via GUI, abackup file is saved on the SD card. The file's name can be changed viabackupFile. So betterdon't delete it! Using the web GUI you can use the upload form to import such a file.

Smarthome/MQTT (optional)

Everything that can be controlled via RFID tags and buttons, can also be controlled via MQTT(excepting toggling WiFi status as this doesn't make sense). All manual interactions (buttons, RFIDtags) are also sent to MQTT in parallel, so everything is always in sync (unlessWifi/MQTT-connection is broken).

In order to use it it's necessary to run a MQTT broker;Mosquitto forinstance. After connecting to it, ESPuino subscribes to all command-topics. State-topics are used topush states to the broker in order to inform others if anything changed (change of volume, newplaylist, new track, you name it).

In my home setup I'm usingopenHAB to "encapsulate" MQTT into a niceGUI, that's accessible via app + web. For further information (and pictures) refer to theopenHABdirectory.

ℹ️ Idescribed asample config for openHAB2. However, meanwhile openHAB3 is available and all the stuff describedcan also be configured via GUI. Be advised that openHAB is pretty complex and you have to spendsome time to get familiar with it.

MQTT topics

Feel free to use your own smarthome environments (instead of openHAB). The MQTT topics available aredescribed as follows.

ℹ️ If you want to send a command to ESPuino, you have to use a cmnd-topicwhereas ESPuino pushes its states back via state-topics. So guess you want to change the volume to8 you have to send this number via topic-variabletopicLoudnessCmnd. Immediately after doing so,ESPuino sends a conformation of this command usingtopicLoudnessState. To get hands on MQTT Irecommend thisone as introduction (covers more thanyou need for ESPuino).

topic-variablerangemeaning
topicSleepCmnd0 or OFFPower off ESPuino immediately
topicSleepStateON or OFFSends ESPuino's last state
topicRfidCmnd12 digitsSet number of RFID tag which 'emulates' an RFID tag (e.g.123789456089)
topicRfidState12 digitsID of current RFID tag (if not a modification card)
topicTrackStateStringSends current track number, total number of tracks and full path of curren track. E.g. "(2/10) /mp3/kinderlieder/Ri ra rutsch.mp3"
topicTrackControlCmnd1 -> 71=stop;2=unused!;3=play/pause;4=next;5=prev;6=first;7=last
topicCoverChangedStateIndicated that the cover image has potentially changed. For performance reasons the application should load the image only if it's visible to the user
topicLoudnessCmnd0 -> 21Set loudness (depends on minVolume / maxVolume)
topicLoudnessState0 -> 21Sends loudness (depends on minVolume / maxVolume
topicSleepTimerCmndEOPPower off after end to playlist
EOTPower off after end of track
EO5TPower off after end of five tracks
1 -> 2^32Duration in minutes to power off
0Deactivate timer (if active)
topicSleepTimerStatevariousSends active timer (EOP,EOT,EO5T,0, ...)
topicStateOnline, OfflineOnline when powering on,Offline when powering off
topicCurrentIPv4IPIPv4-stringSends ESPuino's IP-address (e.g.192.168.2.78)
topicLockControlsCmndON, OFFSet if controls (buttons, rotary encoder) should be locked
topicLockControlsStateON, OFFSends if controls (buttons, rotary encoder) are locked
topicPlaymodeState0 - 10Sends current playback mode (single track, audiobook...; seeplayback modes)
topicRepeatModeCmnd0 - 3Set repeat-mode:0=no;1=track;2=playlist;3=both
topicRepeatModeState0 - 3Sends repeat-mode
topicLedBrightnessCmnd0 - 255Set brightness of Neopixel
topicLedBrightnessState0 - 255Sends brightness of Neopixel
topicBatteryVoltagefloatVoltage (e.g. 3.81)
topicBatterySOCfloatCurrent battery charge in percent (e.g. 83.0)
topicWiFiRssiStateintNumeric WiFi signal-strength (dBm)
topicSRevisionStateStringSoftware-revision

Development and Contributions

Code Formatting

Automatic code formatting viaclang-format is used. The configuration/rules can be found in.clang-format. If you use Visual Studio Code as IDE, the support for this is automaticallyavailable through the C++ extension.

When editing source code, use Ctrl+Shift+I to run the auto-formatting on the file or Ctrl+K Ctrl+Ffor the selected code.

See thedocumentation for moreoptions like run auto-formatting on saving or editing the file.

The CI (via "GitHub Actions") checks changes when they are pushed in order to keep the source codeclean and provide feedback to the developers and maintainers.

To keep the output ofgit blame clean despite the massive changes when introducing new formattingrules, we have a.git-blame-ignore-revs that lists the commits to ignore. In VSCode this should beused automatically if you use the "GitLens" extension. Otherwise make sure you apply the configfragment for git by runninggit config --local include.path ../.gitconfig once in your localclone.


[8]ページ先頭

©2009-2025 Movatter.jp