Getting Started: ESP8266 WeMos D1 Mini Relay Shield (ACR-00016)

Getting Started: ESP8266 WeMos D1 Mini Relay Shield (ACR-00016)

by ACROBOTIC Industries

Overview

Time to complete: 2–10min; Level of difficulty: Beginner

This guide will show you how to use the WeMos D1 Mini and a Relay Shield to switch a small fan on and off wirelessly over Wi-Fi.

List of Materials

  • 1 x WeMos ESP8266 D1 Mini V2 IoT Kit (5-Piece)

Obtaining the Code

For this activity, we'll be using two sketches inside our Ai Demos WeMos repository:

Different than some of the other shields for the WeMos D1 Mini, there are no additional Arduino libraries that need to be installed for working with the Relay Shield.


How Relays Work

Relays are electronic switches, that is, switches controlled by the presence (or not) of an electric current.  These devices are different from the more traditional mechanical switches, where a button or lever needs to be manually set in order to change the state of the switch.

Relay and Switch/Button ComparisonA relay consists of two parts, the control side (coil) and the switching side (terminals).  By applying a voltage and current on the control side, we are able to change the state of the relay's terminals. The question in all our minds at this point is: if we need to apply a voltage and current anyway, then why do we even need a relay?

Relay Operation Diagram

The answer is that they offer a convenient way to separate the control signal from whatever is being switched on and off.  Thus, we can use a low-voltage/low-current signal from our favorite microcontroller to (de)activate the coil, and the relay will then switch the terminals so that a connection is made (broken) and electric current can (not) flow.

Mechanical vs. Solid State Relay

Relays either use an electromagnet or a light-activated transceiver (optoisolator) to make and break the connection of the terminals.  The most common relays have three terminals labeled Normally Open (NO), Common (COM), and Normally Closed (NC).

Relay Operation Animated

The terminals' names describe their states when the relay is off, that is, when no voltage or current is supplied to the coil.  When the control circuit supplies a voltage and current to the coil or optoisolator, the COM terminal connects to the NO terminal and the connection from the NC terminal to the COM terminal is broken.  When the control circuit stops supplying voltage and current, the COM terminal returns to contact the NC terminal, and the connection to the NO terminal is broken.

When working with relays, we must keep in mind what their ratings are.  Starting with whether they can handle AC, DC, or both.  The relay on the WeMos D1 Mini Relay Shield is rated (datasheet):

NO: 5A (250VAC/30VDC), 10A (125VAC), MAX:1250VA/150W
NC: 3A (250VAC/30VDC), 6A (125VAC), MAX:750VA/90W

Notice that ratings change depending on whether you use the NO or NC terminals!s


Soldering The Pins: Wemos D1 Mini

Different than other shields for the WeMos D1 Mini Development Board, the Relay Shield only comes with one set of pin headers (male).  This is because it is meant to sit at the top of any stack due to it's high vertical extent.  Because of this, the Wemos D1 Mini must use a either a female or long female pin header (socket) if we want to stack the Relay Shield on top.

Wemos D1 Mini Relay Shield Pin Headers Selection

So that we can mount the WeMos D1 Mini on a breadboard we'll choose the long female pin header.  To facilitate the soldering process we first secure the pin headers.  One way to do this is to use a breadboard to hold the pin headers in place.

Soldering Long Female Headers To WeMos D1 MiniWe'll make use of the male headers for holding up the long female sockets.  We can then slide the WeMos D1 Mini board through the pins of the female socket.

Soldering Long Female Headers To WeMos D1 Mini

Note that the pins will get hot and it might melt the plastic of the breadboard so as an alteranative you can use tape to secure the pins in.

Soldering Long Female Headers To WeMos D1 Mini

After securing the pins, we solder each one to the board to make a secure connection. Finally, we let the board cool down for a couple of minutes, and then remove it from the breadboard or tape.


Soldering The Pins: Relay Shield

Now, we can proceed in a similar fashion to solder the pins onto the Relay Shield.  For this board, we select the male pin headers that were included with the shield.

Soldering Long Female Headers To WeMos Relay Shield

To facilitate the soldering process we first secure the pin headers onto the board using a breadboard or tape as we did before.

Soldering Long Female Headers To WeMos Relay Shield

We then place the Relay Shield on top so that all of the short ends of the header are sticking through the board with the relay facing up.

Soldering Long Female Headers To WeMos Relay Shield

After securing the pins, we solder each one to the board to make a robust connection.  Finally, we let the board cool down for a couple of minutes, and then remove it from the breadboard or tape.


Wiring: Fan Control

Wiring the WeMos D1 Mini to the Relay Shield is very straight forward, simply stack the Relay Shield on top.

Be careful though, check the pin labels first to ensure the proper orientation of the boards.  Choose a pin (e.g., RST) and make sure it lines up on both boards.

Now, we'll connect the fan itself. As is typical when using a relay, we'll be using an external power supply to power the fan but not the WeMos D1 Mini or Relay Shield themselves, which will be powered from the USB port of the computer we'll use to load our code.

Wemos D1 Mini Fan Control Wiring Diagram

To connect the external power supply we first ensure that it's disconnected from the outlet and that the WeMos D1 Mini is unplugged from the USB cable. We then connect the positive lead of the power supply to the COMMON pin of the relay using the middle screw terminal.

Next, we connect the positive lead of the fan to the NO (normally open) pin of the realy using the screw terminal that's labeled accordingly.

Lastly, we tie together the power supply negative lead (ground) to the negative lead of the fan. We secure this connection by soldering the leads and using heat shrink to prevent accidental shorting.

As shown in the Relay Shield's schematic below, the electrical design includes components in addition to the relay itself. 

Wemos D1 Mini V2 Relay Schematic

The circuitry of the Relay Shield is set up so that the coil (control side) of the relay is connected between 5V and the collector terminal of a transistor.  The base of the transistor is connected to a digital pin of the WeMos D1 Mini board (pin D1 when stacked) so that the state of the transistor–and thus, the state of the coil–can be turned ON and OFF based on whether the pin is at a HIGH (3.3VDC) or LOW (0VDC, ground) voltage.  We can specify the HIGH/LOW state of pin D1 in the code running on the ESP8266.

If we didn't want to use pin D1, we could use a breadboard for the connections.  But the main advantage of using the WeMos is the ability to stack the boards on top of one another.

Once the boards are stacked, we're ready to start testing out our code.


Code Walkthrough: Fan Control

For turning the relay on and off we can use a program that's similar (if not identical) to one for blinking an LED! In our setup() function, we simply use the global variable to configure the D1 pin as an OUTPUT, and initialize its state so that the relay is initially turned off.  Given that we've wired the NO relay pin to our fan, a LOW output on the pin corresponds to a non-energized relay coil, which causes no contact between the NO and Common pins.

The loop() function simply switches states between HIGH and LOW by inverting the output of a digitalRead() on the control pin (D1).  The 4-second delay in the function results in the fan being on and off for that length of time.

uint8_t relay_pin = D1;

void setup()
{
  pinMode(relay_pin, OUTPUT); 
  digitalWrite(relay_pin, LOW);
}

void loop()
{
  digitalWrite(relay_pin, !digitalRead(relay_pin));
  delay(4000);
}

Having successfully tested the operation of the relay, we can move on to use the ESP8266's Wi-Fi capabilities for controlling the fan over the internet!


Code Walkthrough: IoT Fan

For controlling the fan over the internet we add the code that allows us to connect to our local Wi-Fi network, and run a simple webserver.  In the setup() function, we configure the pin as an OUTPUT, use the WiFi object to connect to our local Wi-Fi network, and print out the assigned IP address.  Then, we use the server object to create 2 routes to our ESP8266 application.  We want to print out a "usage message" when a user navigates to the top level path "/", and we want to toggle the relay on and off when a user navigates to the "/toggle-relay" path.

void setup()
{
  pinMode(pin_relay, OUTPUT);
  WiFi.begin(ssid,password);
  Serial.begin(115200);
  while(WiFi.status()!=WL_CONNECTED)
  {
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.print("IP Address: ");
  Serial.print(WiFi.localIP());

  server.on("/", [](){server.send(200,"text/plain","Hello Relay! Navigate to /toggle-relay to turn the Relay On/Off.");});
  server.on("/toggle-relay", toggleRelay);
  server.begin();
}

Using the on() method of the server object, we associate each of the two routes mentioned above with two corresponding functions.  These functions run when the paths are accessed by any client application.

The first function is defined in place, that is, inside the second argument passed of the on() method:

[](){server.send(200,"text/plain","Hello Relay! Navigate to /toggle-relay to turn the Relay On/Off.");}

This function simply calls the send() method of the server object to create an HTTP response with code 200, content-type plain text, and a string of text as its body.  The string contains a usage message to be sent to the client application accessing the top level (/) path.

For the second path, we actually use the function name as the parameter passed to the on() method.  A few lines below, we define what the function actually does:

void toggleRelay()
{
  uint8_t new_state = !digitalRead(pin_relay);
  String new_state_str = (new_state?"ON":"OFF");
  digitalWrite(pin_relay,new_state);
  server.send(200,"text/plain", "Relay is now "+new_state_str+"!");
}

As we intended, the toggleRelay() function toggles the state of the pin connected to the relay.  It also calls the send() method to send an HTTP response to client applications with code 200, content-type plain text, and a body containing a string reporting the new state of the pin.

You can easily use this code to start connecting different devices to the web, and controlling them wirelessly at will!

Leave a comment

  • Please note, comments must be approved before they are published

$1 Days
$2 Hours
$3 Minutes
$4 Second
{ "en":{ "general": { "field": { "required": "Required", "actions": "Actions", "top_btn": "Top" }, "accessibility": { "skip_to_content": "Skip to content", "close_modal": "Close (esc)" }, "meta": { "tags": "Tagged \"[[ tags ]]\"", "page": "Page [[ page ]]" }, "404": { "title": "404 Page Not Found", "subtext": "The page you requested does not exist.", "link": "Continue shopping" }, "pagination": { "previous": "Previous", "next": "Next", "current_page": "Page [[ current ]] of [[ total ]]" }, "password_page": { "opening_soon": "Opening Soon", "login_form_heading": "Enter store using password", "login_form_password_label": "Password", "login_form_password_placeholder": "Your password", "login_form_submit": "Enter", "signup_form_email_label": "Email", "signup_form_success": "We will send you an email right before we open!", "admin_link_html": "Are you the store owner? Log in here<\/a>", "password_link": "Enter using password", "powered_by_shopify_html": "This shop will be powered by [[ shopify ]]" }, "social": { "share_on_facebook": "Share", "share_on_twitter": "Tweet", "share_on_pinterest": "Pin it", "alt_text": { "share_on_facebook": "Share on Facebook", "share_on_twitter": "Tweet on Twitter", "share_on_pinterest": "Pin on Pinterest" } }, "search": { "no_results_html": "Your search for \"[[ terms ]]\" did not yield any results.", "results_with_count": { "one": "[[ count ]] result for \"[[ terms ]]\"", "other": "[[ count ]] results for \"[[ terms ]]\"" }, "title": "Search our site", "placeholder": "Search", "submit": "Submit", "close": "Close search" }, "newsletter_form": { "newsletter_email": "Join our mailing list", "email_placeholder": "Email address", "confirmation": "Thanks for subscribing", "submit": "Subscribe", "show_me_text": "Do not show me again" }, "filters": { "show_more": "Show More", "show_less": "Show Less" }, "breadcrumbs": { "home": "Home", "create_account": "Create account", "account": "Account", "addresses": "Addresses" }, "item": { "remove": "Remove Item" } }, "sections": { "header": { "top_header_login": "Login", "top_header_register": "Register", "top_header_wishlist": "Wish list", "register_dropdown": "No account? Create one here", "forgot": "Forgot password", "all_collection": "All Collections", "world_wide_delivery": "Worldwide delivery", "shipping_text": "Free UK Delivery on orders over £ 100", "hot_line": "Hot line" }, "menu": { "mobile_menu_tab": "Menu", "mobile_account_tab": "Account", "mobile_settings_tab": "Settings" }, "slideshow": { "next_slide": "Next slide", "previous_slide": "Previous slide", "pause_slideshow": "Pause slideshow", "play_slideshow": "Play slideshow", "play_video": "Play video", "close_video": "Close video" }, "map": { "get_directions": "Get directions", "address_error": "Error looking up that address", "address_no_results": "No results for that address", "address_query_limit_html": "You have exceeded the Google API usage limit. Consider upgrading to a Premium Plan<\/a>.", "auth_error_html": "There was a problem authenticating your Google Maps account. Create and enable the JavaScript API<\/a> and Geocoding API<\/a> permissions of your app." } }, "blogs": { "article": { "view_all": "View all", "all_topics": "All topics", "by_author": "by [[ author ]]", "posted_in": "Posted in", "read_more": "Read more", "back_to_blog": "Back to [[ title ]]" }, "comments": { "title": "Leave a comment", "name": "Name", "email": "Email", "message": "Message", "post": "Post comment", "moderated": "Please note, comments must be approved before they are published", "success_moderated": "Your comment was posted successfully. We will publish it in a little while, as our blog is moderated.", "success": "Your comment was posted successfully! Thank you!", "comments_with_count": { "one": "[[ count ]] comment", "other": "[[ count ]] comments" } } }, "cart": { "general": { "title": "Your cart", "note": "Add a note to your order", "remove": "Remove", "subtotal": "Subtotal", "savings": "You're saving", "shipping_at_checkout": "Shipping & taxes calculated at checkout", "update": "Update", "checkout": "Process Check out", "empty": "Your cart is currently empty.", "cookies_required": "Enable cookies to use the shopping cart", "edit": "Edit", "cancel": "Cancel", "continue_shopping": "Continue shopping", "recently_added_item": "Recently added item(s)", "remove_item": "Remove This Item", "view_and_edit_cart": "View and edit cart", "clear": "Clear cart", "empty_page_title": "Shopping Cart is Empty", "here": "here", "empty_continue_html": "Click here to continue shopping.", "processing": "Processing...", "items_count_label" : "[[ count ]] item(s) in your cart", "ok" : "Ok" }, "label": { "product": "Product", "price": "Price", "quantity": "Quantity", "total": "Total", "total_item": "Total item", "sub_total_top": "Cart Subtotal" } }, "collections": { "general": { "view_all": "View all", "clear_all": "Clear All", "no_matches": "Sorry, there are no products in this collection", "items_with_count": { "one": "[[ count ]] product", "other": "[[ count ]] products" }, "load_more": "Load More", "sidebar_btn": "Filter by" }, "sorting": { "title": "Sort by", "manual": "Featured", "best_selling": "Best Selling", "title_ascending": "Alphabetically, A-Z", "title_descending": "Alphabetically, Z-A", "price_ascending": "Price, low to high", "price_descending": "Price, high to low", "created_descending": "Date, new to old", "created_ascending": "Date, old to new" }, "filters": { "title_tags": "Filter", "all_tags": "All products", "categories": "categories", "title": "Filter", "color": "Color", "size": "Size", "brand": "Brand", "price": "Price", "green": "Green", "blue": "Blue", "red": "Red", "pink": "Pink", "black": "Black", "purple": "Purple", "white": "White", "orange": "Orange" }, "product_item": { "quick_shop": "Quick View", "compare": "Compare", "wishlist": "Add to Wishlist" } }, "contact": { "form": { "name": "Name", "email": "Email", "phone": "Phone Number", "message": "Message", "submit": "Submit", "post_success": "Thanks for contacting us. We'll get back to you as soon as possible.", "address": "Address", "telephone": "Telephone", "title": "Write us", "required": "Required" } }, "customer": { "account": { "title": "My Account", "details": "Account Details", "view_addresses": "View Addresses", "return": "Return to Account Details" }, "activate_account": { "title": "Activate Account", "subtext": "Create your password to activate your account.", "password": "Password", "password_confirm": "Confirm Password", "submit": "Activate Account", "cancel": "Decline Invitation" }, "addresses": { "title": "Your Addresses", "default": "Default", "add_new": "Add a New Address", "edit_address": "Edit address", "first_name": "First Name", "last_name": "Last Name", "company": "Company", "address1": "Address1", "address2": "Address2", "city": "City", "country": "Country", "province": "Province", "zip": "Postal\/Zip Code", "phone": "Phone", "set_default": "Set as default address", "add": "Add Address", "update": "Update Address", "cancel": "Cancel", "edit": "Edit", "delete": "Delete", "delete_confirm": "Are you sure you wish to delete this address?" }, "login": { "title": "Login", "desc": "If you have an account, sign in with your email address.", "email": "Email", "password": "Password", "forgot_password": "Forgot your password?", "sign_in": "Sign In", "guest_title": "Continue as a guest", "guest_continue": "Continue" }, "orders": { "title": "Order History", "order_number": "Order", "date": "Date", "payment_status": "Payment Status", "fulfillment_status": "Fulfillment Status", "total": "Total", "none": "You haven't placed any orders yet." }, "order": { "title": "Order [[ name ]]", "date": "Placed on [[ date ]]", "cancelled": "Order Cancelled on [[ date ]]", "cancelled_reason": "Reason: [[ reason ]]", "billing_address": "Billing Address", "payment_status": "Payment Status", "shipping_address": "Shipping Address", "fulfillment_status": "Fulfillment Status", "discount": "Discount", "shipping": "Shipping", "tax": "Tax", "product": "Product", "sku": "SKU", "price": "Price", "quantity": "Quantity", "total": "Total", "fulfilled_at": "Fulfilled [[ date ]]", "subtotal": "Subtotal" }, "recover_password": { "title": "Reset your password", "email": "Email", "submit": "Submit", "cancel": "Cancel", "subtext": "We will send you an email to reset your password.", "success": "We've sent you an email with a link to update your password." }, "reset_password": { "title": "Reset account password", "subtext": "Enter a new password for [[ email ]]", "password": "Password", "password_confirm": "Confirm Password", "submit": "Reset Password" }, "register": { "title": "Create Account", "first_name": "First Name", "last_name": "Last Name", "email": "Email", "password": "Password", "submit": "Create", "desc": "Creating an account is easy. Just fill in the form below." } }, "homepage": { "onboarding": { "product_title": "Your product's name", "product_description": "This area is used to describe your product’s details. Tell customers about the look, feel, and style of your product. Add details on color, materials used, sizing, and where it was made.", "collection_title": "Your collection's name", "blog_title": "Your post's title", "blog_excerpt": "Your store hasn’t published any blog posts yet. A blog can be used to talk about new product launches, tips, or other news you want to share with your customers. You can check out Shopify’s ecommerce blog for inspiration and advice for your own store and blog.", "blog_author": "Author name", "no_content": "This section doesn’t currently include any content. Add content to this section using the sidebar." } }, "layout": { "navigation": { "search": "Search", "toggle": "expand\/collapse", "expand": "expand", "collapse": "collapse", "all_categories": "All Categories" }, "cart": { "title": "Cart", "items_count": { "one": "item", "other": "items" } }, "customer": { "account": "Account", "log_out": "Log out", "logout": "Log out", "log_in": "Log in", "create_account": "Create account", "sign_up": "Sign up", "wishlist": "Wishlist" }, "footer": { "social_platform": "[[ name ]] on [[ platform ]]" }, "list_page": { "grid": "Grid", "list": "List" } }, "products": { "product": { "regular_price": "Regular price", "sold_out": "Sold out", "unavailable": "Unavailable", "on_sale": "Sale", "quantity": "Quantity", "add_to_cart": "Add to cart", "back_to_collection": "Back to [[ title ]]", "related_title": "Related Products", "qty_increase": "Increase", "qty_decrease": "Decrease", "deal_days": "Days", "deal_hours": "Hours", "deal_minutes": "Minutes", "deal_second": "Second", "select_option": "Select Option", "add_to_wishlist": "Add to Wishlist", "add_to_review": "Add to review", "compare_success_msg": "[[ product_title ]] has added to comparing box successful", "compare_exist_msg": "[[ product_title ]] is exist in comparing box", "compare_cart_msg": "[[ product_title ]] has added to shopping cart", "compare_remove_msg": "[[ product_title ]] has removed from comparing box", "compare_remove_msg": "[[ product_title ]] has removed from comparing box", "comparing_box": "Comparing box", "compare_no_items": "There is no items in comparing box", "wishlist_success_msg": "[[ product_title ]] has added to wishlist successful", "wishlist_exist_msg": "[[ product_title ]] is exist in wishlist", "wishlist_cart_msg": "[[ product_title ]] has added to shopping cart", "wishlist_box": "Wishlist", "wishlist_remove_msg": "[[ product_title ]] has removed from wishlist", "wislist_no_items": "There is no items in wishlist", "upsell_cart_msg": "\"[[ product_title ]]\" has added to shopping cart", "upsell_block_title": "Frequently bought with \"[[ product_title ]]\"", "upsell_cart_qty": "[[ count ]] item(s)", "upsell_product_page_title": "You may also like these products", "upsell_checkout_btn": "Checkout", "share": "Share product", "share_on_facebook": "Share on Facebook", "share_on_twitter": "Share on Twitter", "share_on_pinterest": "Share on Pinterest", "share_on_google": "Share on Google+", "share_on_linkedin": "Share on LinkedIn", "availability": "Availability", "in_stock": "In Stock", "out_of_stock": "Out of stock", "quick_overview": "Quick Overview", "details": "Details", "reviews": "Reviews", "first_review": "Be the first review", "tags": "Product Tags", "size_chart": "Size Chart", "options": "Options", "vendor": "Vendor", "features": "Features", "sale_left_text": "[[ sales ]] SOLD. HURRY! ONLY A FEW LEFT!", "checkout_text": "Secured and trusted checkout with" }, "upsell": { "recommend_text": "Someone purchased a", "minute_ago": "minutes ago" } }, "gift_cards": { "issued": { "title_html": "Here's your [[ value ]] gift card for [[ shop ]]!", "subtext": "Your gift card", "disabled": "Disabled", "expired": "Expired on [[ expiry ]]", "active": "Expires on [[ expiry ]]", "redeem_html": "Use this code at checkout to redeem your [[ value ]] gift card", "shop_link": "Start shopping", "print": "Print this gift card", "remaining_html": "[[ balance ]] left", "add_to_apple_wallet": "Add to Apple Wallet" } }, "date_formats": { "month_day_year": "%B %d, %Y" } } }