RFID Süßigkeitenbox + Twitter



Bald ist Weihnachten. Die Vorweihnachtszeit ist eingeläutet. Man wird von oben bis unten mit Süßigkeiten überschüttet. Ob es die klassische Schokolade, die Marzipankartoffeln, Spritzgebäck oder Lebkuchen ist: Alles liegt in greifbarer Nähe und wartet nur darauf gierig verschlungen zu werden.
Jedes Jahr nehme ich mir vor, nicht so viel davon zu essen und jedes Mal verliere ich gegen meinen inneren Schweinehund. Vollgestopft mit Süßkram liege ich jährlich auf der Couch und gelobe, es nächstes Jahr besser zu machen. Dieses Jahr wird das nicht so. Dieses Jahr sorge ich vor:
Ich baue eine Kiste, die sich nur mittels RFID Token öffnen lässt und das auch nur 3x täglich. Haha! Schweinehund ausgetrickst...

Dieses Jahr spielte mir der Zufall etwas in die Hände, da ich Anfang des Monats aus Spaß und Interesse ein paar RFID-Module bestellte und mit denen etwas rumspielte. Mich interessierte, wie sie funktionieren und wie man sie ansteuert, ausliest und beschreibt. Nur fiel mir kein sonderlich guter Anwendungsfall dafür ein. Der Vermieter wird vermutlich nicht sonderlich erfreut sein, wenn jemand die Schließanlage manipuliert und sein Gelöte dazwischen klemmt. Schade. Spießer! Mittlerweile fahre ich 2x die Woche eine etwas längere Strecke zur Arbeit und habe viel Zeit zum Nachdenken. So kam ich während der Fahrt auf die Idee eine Süßigkeitenbox zu bauen, die sich nur via Token öffnen lässt.
Ein paar Skizzen später stand fest, dass die notwendige Technik möglichst nicht sichtbar sein soll und ein doppelter Boden von Nöten ist. Im Zwischenboden soll ein Arduino, als Herz, seinen Platz finden und die Anfrage zum Öffnen des Deckels via WLAN an einen Kontrollserver schicken. Dieser Server muss entscheiden, ob ich meine Süßigkeiten bekomme, oder eben nicht und die entsprechende Antwort zurückschicken. Der Arduino dreht dann einen Servomotor, nach rechts, wodurch der Deckel sich öffnen lässt. Schließt man die Kiste wieder, erkennt dies der Controller mittels Reedkontakt und verriegelt den Deckel.

Folgende Teile werden benötigt:

Wichtig: Das RFID Modul läuft mit 3.3V und ist NICHT 5V kompatibel.

Die Einzelteile werden nun wie folgt zusammengesteckt:



Die LEDs bekommen jeweils einen 220 ohmigen Widerstand verpasst und der Reedkontakt wird mittels PullUp (4,7kOhm) an D2 geklemmt. Die rote LED hängt auf D4, die Grüne auf D3.
Der Servo bekommt seine extra 5V und steckt auf D1.
Das RFID-Modul hängt wie folgt am Board:

Wemos D1RC522
3.3V3.3V
GGND
D0RST
D5SCK
D6MISO
D7MOSI
D8SDA




Nacht etwas Löten sieht das fertige Board dann wie folgt aus:


Um alle Bauteile an Ort und Stelle zu halten, habe ich ein paar Halterungen gedruckt, diese kann man hier oder auf Thingiverse.com runterladen.


Der Servo wird in die passend gedruckte Form hinein geschoben und mittels zwei Schrauben links & rechts verschraubt.
Das RFID Modul wird zwischen die Wand der Kiste und dem "Deckel" geschoben. Verschraubt werden sie von innen nach außen, sodass die Schrauben den Deckel und das Modul gegen die Innenwand drücken.
Der Reedkontakt kann platziert werden wie man auch immer lustig ist. Die Kontakte müssen sich halt lediglich beim Schließen des Deckels möglichst nahe kommen, bestenfalls berühren.
Ich habe den Servo und den Kontakt beide in die gleiche Ecke gebaut, um alles technische in einer "Gegend" zu konzentrieren:

Auf den obigen Bildern ist das verlängerte Servohorn gut zu erkennen. Der Druck wird mittels kurzer Schraube und etwas Kleber auf dem vorhandenem Horn fixiert und dient als Sperre zum Öffnen, wenn der Servo in seine "Ruheposition" gefahren ist. Der Gegenpart, der zum Versperren genutzt wird, besteht aus drei Teilen: Die Bodenplatte wird mit dem Mittelteil mit etwas Aceton verklebt. Die zweite Verbindung mittels einer Schraube, ein paar Unterlegscheiben und einer Mutter verschraubt. So kann man bei Bedarf den Winkel und die Entfernung etwas justieren. Klappt ganz gut: Danke Gehirn! Einfach in den Deckel schrauben. Möglichst so, dass das Horn bereits gut über den Winkel greift.


Alle Leitungen verlaufen dann in den doppelten Boden der Kiste und werden dort an das gelötete Board angeschlossen:
Um die DC Buchse vernünftig am Gehäuse zu befestigen, ist bei den Modellen eine Adapterplatte dabei. Diese wird auf die Buchse gesteckt und mit der Überwurfmutter fixiert. Die Platte wird dann mit zwei kleinen Schrauben an's Gehäuse gespaxt. Die Kabel sollte man vorher am besten schon an die Buchse gelötet haben, sonst wird das etwas eng und unangenehm. Dann noch den MicroUSBStecker anlöten und fertig ist die Sache mit dem Strom:


Hardwaremäßig war's das dann schon. Fehlt noch die richtige Software.

Arduino Code

/* BunteKiste Source.
Some code to handle a crate full of sweets, to open and close it via RFID tokens
by Christian Figge - info ät flazer punked net (flazer.com)
*/

#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Servo.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>

ESP8266WiFiMulti WiFiMulti;

//RFID SPI
#define RST_PIN  D0 
#define SS_PIN   D8

//SERVO
#define SRV_PIN  D1

//REED SWITCH
#define REED_SW  D2

//STATUS LEDS
#define LED_RED  D4
#define LED_GRN  D3

MFRC522 mfrc522(SS_PIN, RST_PIN);

boolean doorState = false;
boolean isOpen = false;
int loopWaitDoorCheck = 0;
int blameCount = 0;

Servo servo;

/**
 * Initialize.
 */
void setup() {
    Serial.begin(57600);
    while (!Serial); 
    SPI.begin();
    mfrc522.PCD_Init();

    WiFiMulti.addAP("YOUR_AP_SSID", "YOUR_AP_PASSWORD");

    servo.attach(SRV_PIN);
    pinMode(REED_SW, INPUT);
    pinMode(LED_RED, OUTPUT);
    pinMode(LED_GRN, OUTPUT);

    //Just light both LEDs for 2 secs
    displayWelcome();
    displayBlame();
    delay(2000);
    ledsOut();

    handleServo(false);
    doorState = getCurrentDoorState();
}

/**
 * Main loop.
 */
void loop() {
    delay(100);
    if(waitForDoorStatusChange()) {
        delay(2000);
        if(!doorState) {
            if(isOpen) {
                handleServo(false);
                isOpen = false;
                ledsOut();
            }
        }
    }

    if(blameCount > 0) {
        blameCounter();
    }

    // Look for new cards
    if (!mfrc522.PICC_IsNewCardPresent())
        return;

    // Select one of the cards
    if (!mfrc522.PICC_ReadCardSerial())
        return;

    MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);

    // Check for compatibility
    if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI
        &&  piccType != MFRC522::PICC_TYPE_MIFARE_1K
        &&  piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
        Serial.println(F("No MIFARE Classic card."));
        return;
    }

    String uid = getID();
    Serial.print("UID: "); Serial.print(uid);
    Serial.println("");

    if(uid != "") {
        if(check(uid)) {
            Serial.println("Simsalabim");
            handleServo(true);
            isOpen = true;
            displayWelcome();
        }else{
            blameCount = 1;
            displayBlame();
        }
    }

    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
}

/**
 * handles time for showing blame led
 */
void blameCounter() {
    blameCount++;
    if(blameCount > 10) {
      ledsOut();
      blameCount = 0;
    }
}

/**
 * fires green led
 */
void displayWelcome() {
    digitalWrite(LED_GRN, 1);
}

/**
 * fires red led
 */
void displayBlame() {
    digitalWrite(LED_RED, 1);
}

/**
 * just blackout both leds
 */
void ledsOut() {
    digitalWrite(LED_RED, 0);
    digitalWrite(LED_GRN, 0);
}

/**
 * returns current lid's state
 */
boolean getCurrentDoorState() {
    boolean status = false;
    if(digitalRead(REED_SW) < 1) {
        status = true;
    }
  return status;
}

/**
 * checks if status of lid changes
 **/
boolean waitForDoorStatusChange() {
    if(doorState != getCurrentDoorState()) {
        doorState = getCurrentDoorState();
        if(!doorState) {
            Serial.println("CLOSED!!!!");
        }else{
            Serial.println("OPENED!!!!");
        }
        return true;
    }
    return false;
}

/**
 *  Sends request to server
 */
boolean check(String uid) {
    boolean result = false;
    if(WiFiMulti.run() != WL_CONNECTED) {
        Serial.println("NOT CONNECTED!");
        return false;
    }
    HTTPClient http;
    Serial.println("[HTTP] begin...");
    http.begin("http:///PATH_TO_YOUR_CONTROLLSERVER/api/crate/" + uid); //HTTP
    Serial.println("[HTTP] GET...");
    int httpCode = http.GET();
    if(httpCode > 0) {
        Serial.printf("[HTTP] GET... code: %d\n", httpCode);
        Serial.println("");
        if(httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            Serial.println(payload);
            if(payload == "granted") {
                result = true;
            }
        }
    }else{
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }
    http.end();
    return result;
}

/**
 * Handles Servo to open/close the crate
 */
void handleServo(boolean direction) {
    int pos;
    if(direction) {
        for(pos = 0; pos <= 120; pos += 1) {
            servo.write(pos);
            delay(1); 
        }
    }else if(!direction) {
        for(pos = 180; pos>=0; pos-=1) {                                
            servo.write(pos);
            delay(1); 
        }
    }
}

/**
 * Get Uid and transform to uppercase
 */
String getID(){
    String code ="";
    for (byte i = 0; i < mfrc522.uid.size; i++) {
        code += String(mfrc522.uid.uidByte[i], HEX) + ":";
    }

    code.remove(code.length()-1);
    code.toUpperCase();
    return code;
}

/**
 * Helper routine to dump a byte array as hex values to Serial.
 */
void dump_byte_array(byte *buffer, byte bufferSize) {
    for (byte i = 0; i < bufferSize; i++) {
        Serial.print(buffer[i] < 0x10 ? " 0" : " ");
        Serial.print(buffer[i], HEX);
    }
}

Ein paar Anmerkungen zum Code:
Der Arduino sendet, nachdem er die Karte eingelesen hat, via WLAN eine Anfrage zu einer API (Webseite). Diese nimmt zwei Parameter entgegen: Die Art des Schlosses (crate) und die UID des Tokens bzw. der Karte. Nun prüft der Webserver, ob die Karte bekannt ist und wie oft die Kiste schon geöffnet wurde. Ist das Limit erreicht, oder die Karte unbekannt, dann antwortet die API mit "denied". Wenn Zugang gewährt wird, dann gibt's ein "granted".

Der Code ist nicht der Sauberste, das liegt an folgenden Punkten:

  • Mein absolutes Unvermögen sauberen Code zu schreiben
  • Mein Versagen C zu verstehen
  • Die benötigte Zeit unterschätzt und dann musste ich mich beeilen

Ein paar Dinge müssen im Code zudem noch angepasst werden:

  • YOUR_AP_SSID - Der Namen des WLANs
  • YOUR_AP_PASSWORD - Das Passwort des WLANs
  • PATH_TO_YOUR_CONTROLLSERVER - URL zur API

Der Code wird nicht direkt lauffähig sein. Zunächst muss die RFID-Library installiert werden. Die findet man auf Github: https://github.com/miguelbalboa/rfid. Dort den "Master" runterladen, entpacken und in den "libraries"-Ordner der Arduino IDE schieben. Jetzt noch das "-master" im Ordnernamen entfernen.
Um das Board überhaupt programmieren zu können, muss nun ersteinmal der Treiber installiert werden, denn das WeMos D1 nutzt nicht den Standard-FTDI-Chip sondern einen Chip mit der Bezeichnung "CH340G". Die Treiber habe ich für Windows hier gefunden: http://www.arduined.eu/tag/ch340g/ bzw. für Mac in Björns Blog: https://blog.sengotta.net/arduino-nano-wird-nicht-erkannt-was-tun/.

Leider reicht das immer noch nicht aus: Jetzt muss noch der Boardtyp mit der Arduino IDE bekannt gemacht werden. Dafür fügt man folgende URL in den Einstellung der IDE in das Feld "Zusätzliche Boardverwalter-URLs" hinzu:
http://arduino.esp8266.com/stable/package_esp8266com_index.json


Falls die URL irgendwann, in ferner Zukunft, mal nicht mehr funktionieren sollte, dann wird ein Blick in das dazugehörige Gitrepo sicherlich hilfreich sein: https://github.com/esp8266/Arduino
Nun muss das Paket noch über den Boardverwalter herunter geladen werden. Dies stößt man an, indem man über "Werkzeuge -> Board -> Boardverwalter" navigiert. Hier sucht man nun nach ESP8266 und installiert den Krempel. Das dauert einen Moment, danach sind ein paar mehr Boards auswählbar:


Juhu! Nun kann man den Code endlich kompilieren und auf's Board laden.

Leider darf ich den Code der API nicht veröffentlichen, da ich Großteile des Backends während meiner Arbeitszeit schrieb (Ja! Unter der Woche habe ich einen normalen Beruf). Wir brauchten dort ein schniekes Adminpanel und so konnte ich Freizeit und Arbeit wunderschön vermischen. Der Programmieraufwand hält sich aber in Grenzen, da ich auf etliche OpenSource-Projekte zurückgegriffen habe. Technische Daten und ein paar Screenshots kann ich aber gerne raushauen.

Der Webserver ist ein Nginx mit PHP-extension auf einem Raspberry Pi. Als Datenbank läuft eine MariaDB. Da ich das Rad nicht (mehr) andauernd neu erfinden möchte, dient Laravel 5.3 als Framework.
Das Theme kommt auch nicht von mir, sondern ist ein freies Admin-Theme namens "Matrix". Dieses habe ich mir mittels Bootstrap und etwas Javascript (JQuery) zurecht gebogen. Nach erfolgreicher Arbeit sieht das Ganze dann so aus:


Nicht sonderlich hübsch, aber es tut was es soll.

Und weil man sich nicht immer nur an OpenSource-Projekten bedienen, sondern auch mal etwas zurückgeben sollte, haben wir eine weitere Twitter-API geschrieben. Die so einfach zu benutzen ist, dass das fast ein bisschen weh tut. Die kann man hier runterladen, oder auch weiter entwickeln: https://github.com/FrozenDonkey/twitter-api-php. Der Code wird auch in der Kiste benutzt und twittert zufällige Texte, je nachdem, ob der Zugriff erlaubt oder verboten wird.

Wie bindet man den Code ein?
Ganz einfach:

  • Runterladen
  • Entpacken
  • Bei Twitter einen Devaccount erstellen (https://dev.twitter.com)
  • Eine App erstellen -> https://apps.twitter.com
  • In der index.php folgenden Block anpassen:
    $twitter = new TwitterAPI(
    "YOUR_OAUTH_ACCESS_TOKEN",
    "YOUR_OAUTH_ACCESS_TOKEN_SECRET",
    "YOUR_CONSUMER_KEY",
    "YOUR_CONSUMER_SECRET"
    );

    Nun kann ein Tweet mit folgender Zeile gesendet werden:

    $res = $twitter->tweet("THIS IS YOUR TWEET");

    Möchte man ein Bild mit anhängen, dann geht das so:

    $res = $twitter->tweetImage('THIS IS A TWEET WITH AN IMAGE', 'path/to/image.jpg');

    Voll einfach, oder?


    Die Box sieht, nachdem Bracka noch ein Logo draufgepinselt hat, so aus:



    Twittern tut sie unter dem Namen @DieBunteKiste. Kannste ja mal reingucken, wenn du Bock hast.


    Hier gibt's auch noch ein Video von der ganzen Bastelei:

33 Kommentare

Jonas schrieb am 30.11.2016 00:55:
Danke für die Anleitung Versuch grad die Box nachzubauen, da kommt der Blogeintrag gerade richtig dass das Projekt bis Weihnachten fertig wird. :)
Tjard schrieb am 30.11.2016 13:50:
Welchen API code
flazer schrieb am 30.11.2016 13:54:
Was genau meinst du? TwitterAPI, oder die API auf dem Webserver?
Tjard schrieb am 30.11.2016 14:52:
du hast geschrieben das die api während der aerbeit entstanden seie
Tjard schrieb am 30.11.2016 14:59:
hab's schon kapiert verstehe nur php nicht so gut:(((( muss mich um meine Künste in dieser Sprache noch kümmern hab ja aber noch ein paar Schuljahre vor mir ;)
0 schrieb am 01.12.2016 05:59:
Ich wollte Mal Fragen wie ich es ohne Internet mache (also nur das man nur 3 Mal am Tag was nehmen kann).
Tjard schrieb am 01.12.2016 07:28:
Nein doch statt dem WLAN ne Variable die kleiner als drei sein muss und bei jedem Öffnen um 1 erhöht wird
MaX schrieb am 01.12.2016 21:02:
Wie programmiert man dann das es sich täglich resetet?
Man könnte nach den drei versuchen ja einfach eine enorm große Waartezeit eingeben, aber so macht das jakeinen Spaß
Tjard schrieb am 02.12.2016 07:31:
Man kann mit PHP auch ne Zeit Anzeige programmieren und daraus die Werte ziehen
Tjard schrieb am 02.12.2016 07:40:
Was ist mit your oauth accesse Token gemeint?
flazer schrieb am 02.12.2016 08:34:
Die Begrenzung auf 3x am Tag regelt die Datenbank der API. Diese schaut nach, wie oft am Tag die Kiste von XY bereits geöffnet wurde und reagiert dementsprechend. Das passiert also nicht in der Box selbst, sondern auf dem Raspberry.
flazer schrieb am 02.12.2016 08:35:
Hey Tjard,
schau mal hier vorbei: https://dev.twitter.com/oauth/overview Die Tokens bekommst du, wenn du bei Twitter eine App anlegst.
Peter schrieb am 04.12.2016 09:55:
wie heisst das CAD Zeichenprogramm?
NoneType(null) schrieb am 04.12.2016 13:30:
Sorry, wenn ich was blöd frage, aber wie heißt diese Pappe wo du die Hardware drauf lötest?
flazer schrieb am 04.12.2016 14:27:
Das "Programm" ist Tinkercad.com und die "Pappe" nennt sich Lochraster:. Guck mal hier: https://www.reichelt.de/Lochraster-Loetpunkte/2/index.html?ACTION=2&GROUPID=7785 G
DickesKind schrieb am 04.12.2016 15:18:
Servus Chris,
ich würde gern für mein Werkstatt-Verein ein RFID-System aufbauen bei welchem man über die Karte steuern kann wer zu welchen Maschinen Zugriff hat und wer nicht. D.h. das gleiche Problem wie du hier lösen. Den Arduino-Teil kann ich verstehen aber die Webinterface Sache ist mir total fremd. Hast du hier paar Stickpunkte die ich in Google hauen kann damit ich mir sowas auch machen kann oder ist das zu hoch für einen Maschbauer?
Gruß Paul
Jascha schrieb am 10.12.2016 15:24:
Moin,

hab die Hardware auf dem Steckbrett schon aufgebaut und das Sketch auch erfolgreich geladen. Irgendwie zuckt der Servo permanent und wird ziemlich heiß...

Kannst du vielleicht den Teil auf dem Arduino nochmal genauer beschreiben? Verstehe da nur Bahnhof :D
Jonas schrieb am 13.12.2016 23:33:
Moin ich habe deine Box nachgebaut und wollte gerade mal den sketch kompilieren jedoch bekomme ich nun folgende Meldung :
warning: espcomm_sync failed
error: espcomm_open failed
error: espcomm_upload_mem failed
error: espcomm_upload_mem failed
Kann mir dabei jemand weiter helfen?
Max schrieb am 26.12.2016 10:21:
Moin,

habe heute begeistert begonnen das Projekt umzusetzen - leider scheitere ich beim Kompilieren. Ich erhalte folgende Fehlermeldung:

WARNUNG: Bibliothek rfid behauptet auf [avr Architektur(en) ausgeführt werden zu können und ist möglicherweise inkompatibel mit Ihrem derzeitigen Board, welches auf STM32F1 Architektur(en) ausgeführt wird.
C:\Users\Max\Desktop\SussigkeitenBox\SussigkeitenBox.ino: In function 'void setup()':

SussigkeitenBox:56: error: 'displayWelcome' was not declared in this scope

displayWelcome();

^
[...]

Meine Einstellungen für das Board: https://img3.picload.org/image/raowlggo/einstellungen.jpg

Kannst du mir einen Hinweis geben woran das liegen kann?

Danke vorab und Gruß aus Hannover,

Max
Robiotik schrieb am 28.12.2016 00:20:
Voll Coole Idee Sowas zu Bauen, wie währe es wenn man das Als Getränke Automat Verwendet?
flazer schrieb am 29.12.2016 07:15:
Hey Robiotik:
Klingt cool. Aber ich wüsste nicht, wohin mit dem Ding. :D
flazer schrieb am 29.12.2016 07:16:
Hey Max:
Das ist "normal". Einfach ignorieren. Bei mir läuft's trotzdem.
Max schrieb am 04.01.2017 00:21:
Hey Christian,

hoffe du bist gut ins neue Jahr gekommen!

Danke für den Tipp, ich habe es jetzt nochmal ausgeführt und nun funktioniert es (auch ohne Anzeige der anderen Fehler...) - keine Ahnung was da schief gelaufen ist.

Ich würde gerne die Box umgehen und das ganze in meinen Schrank einbauen - aber leider ist der RFID- Empfänger zu schwach durch das 1 cm dicke Holz zu kommen :(

Ist es möglich über den Anschluss dieses Moduls den Empfangsbereich zu vergrößern?: https://picload.org/image/rappwawl/s-l500.jpg

Danke vorab und eine schöne Woche!

LG

Max
Arduino-Freak schrieb am 21.01.2017 07:09:
Hi Flazer,

bin ein großer Fan von deinen Projekten.
Habe allerdings ein paar Fragen:

1.Was für eine Krimpzange benutzt du und welche "Steckerhülsen" aus Plastik mit welchen Aderhülsen?

2.Habe mir ein Termometer mit einem DHT-11 und einem Nano gebaut und wollte fragen ob du/sie auch Mal was in diese Richtung machen könntest/können.

Freue mich schon auf die Antworten und Danke im Voraus.

LG Arduino-Freak
Yugee schrieb am 09.02.2017 15:07:
Ich hätte da auch mal schnell eine Frage. Wie nennt sich diese Testplatine, wo man erstmal Kreisläufe ausprobieren kann. Mfg
Arduino-Freak schrieb am 10.02.2017 06:11:
Das nennt sich Steckplatine...
sebi schrieb am 28.03.2017 14:05:
wie öffnet man die Einstellungen wo man die Bordverwaltung URLs eingeben kann
sebi schrieb am 28.03.2017 20:13:
geht das ganze auch auf Windows weil jedes mal wenn ich bei Bordverwaltung esp 8266 eingebe findet der nichts.
bitte um schnelle antwort

danke schon im voraus

mfg sebastian
sebi schrieb am 30.03.2017 17:15:
Braucht mann für das ganze ein Resperry pie
Lennart schrieb am 10.04.2017 23:02:
Hi

Wo kaufst du deine Litze? Ein Link würde mich freuen.

Wenn es keine zu großen Umstände macht, würde ich mich über eine Antwort per E-Mail freuen: lennih14@gmail.com
c0de schrieb am 27.07.2017 10:28:
dieses aperture science raspberry pi gehäuse, wo hast du das gefunden oder ist es selbst gemacht? kannst du es mal zum download anbieten oder in die tinkercad gallery stellen?

mfg c0de
Chris schrieb am 27.07.2017 11:30:
Moin c0de. Das ist nur ein modifiziertes Standardcase, was ich mal gemacht habe, weil mir die ganzen Himbeeren auf den Sack gingen. https://www.thingiverse.com/thing:677214
Tjard schrieb am 29.07.2017 22:40:
Hiii wieviele Pwm pins hat das WeMos D1 mini?
Name oder Nickname:
Kommentar: