Learning Hubs
  • ← All Modules
  1. Tools & References
  2. 20  Quick Reference Cards
Learning Hubs
  • 1  Introduction to Learning Hubs
  • Navigation & Discovery
    • 2  Learning Hubs
    • 3  Knowledge Map
    • 4  Visual Concept Map
    • 5  Interactive Concept Navigator
    • 6  Learning Paths
    • 7  Learning Recommendations
    • 8  Role-Based Learning Paths
  • Quizzes & Simulations
    • 9  Quiz Navigator
    • 10  Simulation Playground
    • 11  Simulation Learning Workflow
    • 12  Simulation Catalog
    • 13  Simulation Resources
    • 14  Hands-On Labs Hub
  • Tools & References
    • 15  Tool Discovery Hub
    • 16  Troubleshooting Hub
    • 17  Troubleshooting Flowchart
    • 18  IoT Failure Case Studies
    • 19  Discussion Prompts Hub
    • 20  Quick Reference Cards
    • 21  IoT Code Snippet Library
  • Knowledge Tracking
    • 22  Knowledge Gaps Tracker
    • 23  Gap Closure Process
    • 24  Knowledge Categories & Refreshers
    • 25  Progress Tracking & Assessment
    • 26  Video Gallery
    • 27  Quick Reference: Key Concepts

On This Page

  • 20.1 Learning Objectives
  • 20.2 Quick Reference Cards
  • 20.3 Protocol Quick Reference
  • 20.4 Interactive Formula Reference
  • 20.5 Formula Cards
  • 20.6 Pin-Out Reference
  • 20.7 Common Patterns
  • 20.8 Conversion Tables
  • 20.9 See Also
  • Common Pitfalls
  • 20.10 What’s Next
  • 20.11 Related Resources
  1. Tools & References
  2. 20  Quick Reference Cards

20  Quick Reference Cards

Condensed Cheat Sheets for IoT Development

20.1 Learning Objectives

After completing this chapter, you will be able to:

  • Compare key parameters of MQTT, CoAP, BLE, and LoRaWAN protocols using concise reference tables
  • Apply essential IoT formulas for free-space path loss, link budget, battery life, and ADC resolution
  • Identify correct ESP32 pin assignments for ADC, I2C, SPI, UART, and touch interfaces
  • Use common IoT design patterns for sensor reading, MQTT connection, and deep sleep
For Beginners: Quick Reference Cards

These are printable cheat sheets – compact summaries of the most commonly needed IoT information, like protocol parameters, pin assignments, and formulas. They are designed to sit next to your computer while you work, saving you from flipping back through long chapters to find a specific number or setting. If you have ever used a keyboard shortcut reference card, these serve the same purpose for IoT development.

In 60 Seconds

Print-ready cheat sheets covering MQTT (QoS levels, topic structure, wildcards), CoAP (message types, methods, options), BLE (GATT structure, advertising), Zigbee (network roles, profiles), LoRaWAN (classes, spreading factors), ESP32 pin-outs, common formulas (link budget, battery life, data rates), and HTTP status codes. Designed for quick reference during development or lab work.

Key Concepts
  • Quick Reference Card: Compact summary of a technical concept including definition, key properties, use cases, and critical parameters — designed for rapid recall, not initial learning
  • Protocol Summary Card: Compact comparison of IoT protocol properties (range, data rate, power, latency, cost) enabling quick selection for deployment scenarios
  • Formula Reference: Quick-access collection of key IoT calculation formulas (latency budget, link budget, bandwidth savings, battery life) with units and typical values
  • Decision Tree Quick Reference: Simplified flowchart for common IoT design decisions (protocol selection, edge vs. cloud) that can be applied in the field without full reference materials
  • Cheat Sheet: Informal quick reference optimized for exam or interview preparation, covering high-frequency concepts and their distinguishing characteristics
  • Spaced Recall: Using reference cards as prompts to practice retrieving information from memory before consulting the answer, reinforcing retention
  • Worked Example Card: Quick reference combining formula with a concrete numerical example to show how theoretical relationships apply to realistic IoT scenarios
  • Comparison Matrix: Reference format showing multiple options (protocols, architectures, hardware) across consistent criteria dimensions for side-by-side evaluation
Chapter Scope (Avoiding Duplicate Hubs)

This chapter focuses on fast lookup during implementation.

  • Use Code Snippet Library for full runnable examples.
  • Use Troubleshooting Flowchart for fault diagnosis, not static parameter lookup.
  • Use this chapter when you need trusted constants, pin maps, and protocol quick comparisons while building.

20.2 Quick Reference Cards

Print-Ready Reference

These cards are designed to be printed or kept open as quick references during development. Each card fits on a single page.

No-One-Left-Behind Reference Loop
  1. Read the quick card first for baseline values.
  2. Validate one value with a simulator or measurement.
  3. Apply the matching code pattern from the snippet library.
  4. Reinforce with one short challenge in the games hub.

20.3 Protocol Quick Reference

20.3.1 MQTT Cheat Sheet

Show code
html`
<div class="quick-ref-card" style="background: linear-gradient(135deg, #16A085 0%, #1ABC9C 100%); color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h3 style="margin-top: 0; border-bottom: 2px solid rgba(255,255,255,0.3); padding-bottom: 10px;">MQTT Protocol</h3>

  <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px;">
    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Connection</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
Port: 1883 (TCP), 8883 (TLS)
WebSocket: 80/443
Keep-Alive: 60s default
Clean Session: true/false</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">QoS Levels</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
QoS 0: At most once (fire & forget)
QoS 1: At least once (with PUBACK)
QoS 2: Exactly once (4-way handshake)</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Topic Wildcards</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
+ = single level: sensors/+/temp
# = multi level:  sensors/#
$ = system topics: $SYS/#</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Packet Types</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
CONNECT/CONNACK - Establish connection
PUBLISH/PUBACK  - Send message
SUBSCRIBE/SUBACK - Subscribe topic
PINGREQ/PINGRESP - Keep alive</pre>
    </div>
  </div>

  <div style="margin-top: 15px; font-size: 12px; opacity: 0.9;">
    <strong>Best Practice:</strong> Use QoS 0 for telemetry, QoS 1 for commands, retain for status
  </div>
</div>
`

20.3.2 CoAP Cheat Sheet

Show code
html`
<div class="quick-ref-card" style="background: linear-gradient(135deg, #3498DB 0%, #2980B9 100%); color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h3 style="margin-top: 0; border-bottom: 2px solid rgba(255,255,255,0.3); padding-bottom: 10px;">CoAP Protocol</h3>

  <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px;">
    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Connection</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
Port: 5683 (UDP), 5684 (DTLS)
Max message: 1024 bytes (typical)
URI: coap://host:port/path</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Methods (like HTTP)</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
GET    - Read resource
POST   - Create/process
PUT    - Update resource
DELETE - Remove resource</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Message Types</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
CON - Confirmable (needs ACK)
NON - Non-confirmable
ACK - Acknowledgment
RST - Reset (error)</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Response Codes</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
2.01 Created    4.04 Not Found
2.04 Changed    4.05 Not Allowed
2.05 Content    5.00 Server Error</pre>
    </div>
  </div>

  <div style="margin-top: 15px; font-size: 12px; opacity: 0.9;">
    <strong>Key Feature:</strong> Observe option for pub/sub-like notifications on resource changes
  </div>
</div>
`

20.3.3 BLE Cheat Sheet

Show code
html`
<div class="quick-ref-card" style="background: linear-gradient(135deg, #9B59B6 0%, #8E44AD 100%); color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h3 style="margin-top: 0; border-bottom: 2px solid rgba(255,255,255,0.3); padding-bottom: 10px;">Bluetooth Low Energy</h3>

  <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px;">
    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Specifications</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
Frequency: 2.4 GHz (40 channels)
Range: 10-100m typical
Data rate: 125kbps - 2Mbps
MTU: 20 bytes (default), 512 max</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">GATT Structure</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
Profile -> Service -> Characteristic
Service UUID: 16-bit or 128-bit
Characteristic: Read/Write/Notify</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Common UUIDs</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
0x180F - Battery Service
0x2A19 - Battery Level
0x180A - Device Info
0x1801 - Generic Attribute</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #F1C40F;">Roles</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
Central: Scans, initiates connection
Peripheral: Advertises, accepts conn
Server: Has GATT database
Client: Reads/writes characteristics</pre>
    </div>
  </div>

  <div style="margin-top: 15px; font-size: 12px; opacity: 0.9;">
    <strong>Power Tip:</strong> Use notifications instead of polling, keep connection intervals long
  </div>
</div>
`

20.3.4 LoRaWAN Cheat Sheet

Show code
html`
<div class="quick-ref-card" style="background: linear-gradient(135deg, #E67E22 0%, #F39C12 100%); color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h3 style="margin-top: 0; border-bottom: 2px solid rgba(255,255,255,0.3); padding-bottom: 10px;">LoRaWAN</h3>

  <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px;">
    <div>
      <h4 style="margin: 10px 0 5px 0; color: #FFFFFF;">Specifications</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
EU868: 868 MHz (1% duty cycle)
US915: 915 MHz (no duty cycle)
Range: 2-15km (urban to rural)
Payload: 51-222 bytes (SF dependent)</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #FFFFFF;">Spreading Factors</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
SF7:  -123dBm, 5.5kbps, short range
SF10: -132dBm, 980bps, medium
SF12: -137dBm, 250bps, max range
Higher SF = longer range, less speed</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #FFFFFF;">Device Classes</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
Class A: RX after TX only (lowest power)
Class B: Scheduled RX windows
Class C: Always listening (highest power)</pre>
    </div>

    <div>
      <h4 style="margin: 10px 0 5px 0; color: #FFFFFF;">Activation</h4>
      <pre style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; font-size: 12px; margin: 0;">
OTAA: Over-The-Air (recommended)
  - DevEUI, AppEUI, AppKey
ABP: Activation By Personalization
  - DevAddr, NwkSKey, AppSKey</pre>
    </div>
  </div>

  <div style="margin-top: 15px; font-size: 12px; opacity: 0.9;">
    <strong>Duty Cycle:</strong> EU868 = 1% = max 36 sec/hour TX time. Plan message frequency accordingly!
  </div>
</div>
`

20.4 Interactive Formula Reference

20.4.1 Interactive Calculators

Show code
viewof distance_m = Inputs.range([1, 20000], {
  value: 1000,
  step: 100,
  label: "Distance (m)"
})

viewof frequency_mhz = Inputs.select([433, 868, 915, 2400, 5800], {
  value: 868,
  label: "Frequency (MHz)"
})

fspl_db = 20 * Math.log10(distance_m) + 20 * Math.log10(frequency_mhz * 1e6) - 147.55

html`
<div class="quick-ref-card" style="background: linear-gradient(135deg, #16A085 0%, #1ABC9C 100%); color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h4 style="margin: 0 0 15px 0; border-bottom: 2px solid rgba(255,255,255,0.3); padding-bottom: 10px;">Free Space Path Loss Calculator</h4>

  <div style="background: rgba(255,255,255,0.15); padding: 15px; border-radius: 8px; font-family: monospace; font-size: 16px; margin-bottom: 15px;">
    <div style="text-align: center;">
      <div style="font-size: 36px; font-weight: bold; margin: 10px 0;">${fspl_db.toFixed(1)} dB</div>
      <div style="font-size: 14px; opacity: 0.9;">Path loss at ${distance_m.toLocaleString()}m @ ${frequency_mhz} MHz</div>
    </div>
  </div>

  <div style="font-size: 12px; opacity: 0.85;">
    Formula: FSPL(dB) = 20log₁₀(d) + 20log₁₀(f) - 147.55
  </div>
</div>
`
Show code
viewof tx_power = Inputs.range([-10, 30], {
  value: 14,
  step: 1,
  label: "TX Power (dBm)"
})

viewof tx_gain = Inputs.range([0, 10], {
  value: 2,
  step: 0.5,
  label: "TX Antenna Gain (dBi)"
})

viewof rx_gain = Inputs.range([0, 10], {
  value: 2,
  step: 0.5,
  label: "RX Antenna Gain (dBi)"
})

viewof path_loss = Inputs.range([60, 150], {
  value: 91,
  step: 1,
  label: "Path Loss (dB)"
})

viewof fade_margin = Inputs.range([0, 30], {
  value: 10,
  step: 1,
  label: "Fade Margin (dB)"
})

rx_power = tx_power + tx_gain + rx_gain - path_loss - fade_margin

html`
<div class="quick-ref-card" style="background: linear-gradient(135deg, #3498DB 0%, #2980B9 100%); color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h4 style="margin: 0 0 15px 0; border-bottom: 2px solid rgba(255,255,255,0.3); padding-bottom: 10px;">Link Budget Calculator</h4>

  <div style="background: rgba(255,255,255,0.15); padding: 15px; border-radius: 8px; margin-bottom: 15px;">
    <div style="text-align: center;">
      <div style="font-size: 36px; font-weight: bold; font-family: monospace; margin: 10px 0;">${rx_power.toFixed(1)} dBm</div>
      <div style="font-size: 14px; opacity: 0.9;">Received Power</div>
    </div>
  </div>

  <div style="display: grid; grid-template-columns: 1fr auto 1fr; gap: 10px; align-items: center; font-size: 13px; font-family: monospace;">
    <div>TX Power: ${tx_power} dBm</div>
    <div>+</div>
    <div>TX Gain: ${tx_gain} dBi</div>
    <div>RX Gain: ${rx_gain} dBi</div>
    <div>-</div>
    <div>Path Loss: ${path_loss} dB</div>
    <div>Fade Margin: ${fade_margin} dB</div>
    <div>-</div>
    <div></div>
  </div>
</div>
`
Show code
viewof battery_capacity = Inputs.range([100, 5000], {
  value: 2400,
  step: 100,
  label: "Battery Capacity (mAh)"
})

viewof active_current = Inputs.range([1, 100], {
  value: 30,
  step: 1,
  label: "Active Current (mA)"
})

viewof sleep_current = Inputs.range([0.001, 10], {
  value: 0.001,
  step: 0.001,
  label: "Sleep Current (mA)"
})

viewof active_time = Inputs.range([1, 1000], {
  value: 40,
  step: 10,
  label: "Active Time per Event (ms)"
})

viewof events_per_hour = Inputs.range([1, 100], {
  value: 6,
  step: 1,
  label: "Events per Hour"
})

avg_current = ((sleep_current * (3600 - events_per_hour * active_time / 1000)) +
               (active_current * events_per_hour * active_time / 1000)) / 3600

battery_hours = (battery_capacity * 0.8) / avg_current
battery_days = battery_hours / 24
battery_years = battery_days / 365

html`
<div class="quick-ref-card" style="background: linear-gradient(135deg, #9B59B6 0%, #8E44AD 100%); color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h4 style="margin: 0 0 15px 0; border-bottom: 2px solid rgba(255,255,255,0.3); padding-bottom: 10px;">Battery Life Calculator</h4>

  <div style="background: rgba(255,255,255,0.15); padding: 15px; border-radius: 8px; margin-bottom: 15px;">
    <div style="text-align: center;">
      <div style="font-size: 36px; font-weight: bold; font-family: monospace; margin: 10px 0;">${battery_years.toFixed(1)} years</div>
      <div style="font-size: 14px; opacity: 0.9;">${battery_days.toFixed(0)} days | ${battery_hours.toFixed(0)} hours</div>
      <div style="font-size: 13px; opacity: 0.8; margin-top: 5px;">Average current: ${avg_current.toFixed(4)} mA</div>
    </div>
  </div>

  <div style="font-size: 12px; opacity: 0.85;">
    Using 80% of rated capacity. Active ${(events_per_hour * active_time / 1000).toFixed(1)}s/hour, Sleep ${(3600 - events_per_hour * active_time / 1000).toFixed(1)}s/hour.
  </div>
</div>
`
Show code
viewof vref = Inputs.range([1.0, 5.0], {
  value: 3.3,
  step: 0.1,
  label: "Reference Voltage (V)"
})

viewof adc_bits = Inputs.select([8, 10, 12, 16, 24], {
  value: 12,
  label: "ADC Bits"
})

adc_steps = Math.pow(2, adc_bits)
adc_resolution = (vref / adc_steps) * 1000 // in mV

html`
<div class="quick-ref-card" style="background: linear-gradient(135deg, #E67E22 0%, #F39C12 100%); color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h4 style="margin: 0 0 15px 0; border-bottom: 2px solid rgba(255,255,255,0.3); padding-bottom: 10px;">ADC Resolution Calculator</h4>

  <div style="background: rgba(255,255,255,0.15); padding: 15px; border-radius: 8px; margin-bottom: 15px;">
    <div style="text-align: center;">
      <div style="font-size: 36px; font-weight: bold; font-family: monospace; margin: 10px 0;">${adc_resolution.toFixed(2)} mV</div>
      <div style="font-size: 14px; opacity: 0.9;">Per step (${adc_steps.toLocaleString()} steps total)</div>
    </div>
  </div>

  <div style="font-size: 12px; opacity: 0.85;">
    Formula: Step = V<sub>ref</sub> / 2<sup>bits</sup> = ${vref}V / ${adc_steps.toLocaleString()} = ${adc_resolution.toFixed(2)} mV
  </div>
</div>
`

20.5 Formula Cards

Show code
html`
<div class="quick-ref-card" style="background: #2C3E50; color: white; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h3 style="margin-top: 0; border-bottom: 2px solid #16A085; padding-bottom: 10px;">IoT Formulas</h3>

  <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px;">

    <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;">
      <h4 style="margin: 0 0 10px 0; color: #16A085;">Free Space Path Loss</h4>
      <div style="font-family: monospace; font-size: 14px; margin-bottom: 10px;">
        FSPL(dB) = 20log₁₀(d) + 20log₁₀(f) - 147.55
      </div>
      <div style="font-size: 12px; color: #BDC3C7;">
        d = distance (m), f = frequency (Hz)<br>
        At 1km, 868MHz: 91.3 dB loss
      </div>
    </div>

    <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;">
      <h4 style="margin: 0 0 10px 0; color: #16A085;">Link Budget</h4>
      <div style="font-family: monospace; font-size: 14px; margin-bottom: 10px;">
        Prx = Ptx + Gtx + Grx - PathLoss - Margin
      </div>
      <div style="font-size: 12px; color: #BDC3C7;">
        Prx > Sensitivity = link works<br>
        Typical margin: 10-20 dB
      </div>
    </div>

    <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;">
      <h4 style="margin: 0 0 10px 0; color: #16A085;">Battery Life</h4>
      <div style="font-family: monospace; font-size: 14px; margin-bottom: 10px;">
        Hours = Capacity(mAh) / Avg_Current(mA)
      </div>
      <div style="font-size: 12px; color: #BDC3C7;">
        Avg = (Iactive × Tactive + Isleep × Tsleep) / Total<br>
        Use 80% of rated capacity
      </div>
    </div>

    <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;">
      <h4 style="margin: 0 0 10px 0; color: #16A085;">ADC Resolution</h4>
      <div style="font-family: monospace; font-size: 14px; margin-bottom: 10px;">
        Step = Vref / 2^bits
      </div>
      <div style="font-size: 12px; color: #BDC3C7;">
        10-bit, 3.3V: 3.2mV/step<br>
        12-bit, 3.3V: 0.8mV/step
      </div>
    </div>

    <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;">
      <h4 style="margin: 0 0 10px 0; color: #16A085;">Nyquist Sampling</h4>
      <div style="font-family: monospace; font-size: 14px; margin-bottom: 10px;">
        Fs > 2 × Fmax
      </div>
      <div style="font-size: 12px; color: #BDC3C7;">
        Sample at 2x highest frequency<br>
        Practical: use 5-10x for safety
      </div>
    </div>

    <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;">
      <h4 style="margin: 0 0 10px 0; color: #16A085;">SNR (dB)</h4>
      <div style="font-family: monospace; font-size: 14px; margin-bottom: 10px;">
        SNR = 10log₁₀(Psignal / Pnoise)
      </div>
      <div style="font-size: 12px; color: #BDC3C7;">
        ADC theoretical: SNR = 6.02×bits + 1.76<br>
        10-bit: 62dB, 12-bit: 74dB
      </div>
    </div>

  </div>
</div>
`
Putting Numbers to It

Let’s design a LoRaWAN sensor for EU868 using the formulas above. Goal: 5-year battery life on 2× AA batteries (2400 mAh).

Step 1: Choose spreading factor

  • Urban environment, gateway at 500m
  • Free Space Path Loss: \(\text{FSPL} = 20\log_{10}(500) + 20\log_{10}(868 \times 10^6) - 147.55 = 85.5\,\text{dB}\)
  • Link budget: \(P_{rx} = 14\,\text{dBm} + 2\,\text{dBi} + 2\,\text{dBi} - 85.5\,\text{dB} - 10\,\text{dB margin} = -77.5\,\text{dBm}\)
  • SF7 sensitivity is -123 dBm → link margin = \(-123 - (-77.5) = 45.5\,\text{dB}\) → SF7 works comfortably

Step 2: Calculate airtime and duty cycle

  • Payload: 12 bytes, SF7 → airtime ≈ 40 ms
  • EU868 duty cycle: 1% = 36 seconds TX per hour max
  • Messages allowed per hour: \(36\,\text{s} \div 0.04\,\text{s} = 900\) messages/hour max
  • We want 1 message every 10 minutes = 6 messages/hour → well within duty cycle (OK)

Step 3: Battery life calculation \[ \begin{align} \text{Sleep current: } & 1\,\mu\text{A}\\ \text{TX current: } & 30\,\text{mA} \text{ @ 14 dBm}\\ \text{TX time: } & 40\,\text{ms per message}\\ \text{Messages: } & 6/\text{hour} = 144/\text{day} \end{align} \]

Average current: \[ I_{avg} = \frac{1\,\mu\text{A} \times (24 \times 3600 - 144 \times 0.04) + 30\,\text{mA} \times (144 \times 0.04)}{24 \times 3600} = 0.0487\,\text{mA} \]

Battery life: \((2400\,\text{mAh} \times 0.8) \div 0.0487\,\text{mA} = 39,424\,\text{hours} = 1,643\,\text{days} = 4.5\,\text{years}\) (OK)

Key insight: Sleep current dominates! Even though TX is 30 mA vs 1 µA sleep, the device spends 99.93% of time sleeping. Reducing sleep current from 1 µA to 0.5 µA gains 1.25 years; reducing TX power from 14 dBm to 10 dBm (15 mA) only gains 2 months.


20.6 Pin-Out Reference

20.6.1 ESP32 Quick Reference

Show code
html`
<div style="background: #f8f9fa; padding: 20px; border-radius: 12px; margin: 15px 0;">
  <h4 style="margin-top: 0; color: #2C3E50;">ESP32 DevKit Pin Functions</h4>

  <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 15px;">
    <div style="background: white; padding: 12px; border-radius: 8px; border-left: 4px solid #E74C3C; min-width: 0;">
      <strong style="color: #E74C3C;">Power</strong><br>
      <code style="font-size: 12px; white-space: normal; overflow-wrap: anywhere; display: block; line-height: 1.5;">3.3V, 5V, GND</code>
    </div>

    <div style="background: white; padding: 12px; border-radius: 8px; border-left: 4px solid #27AE60; min-width: 0;">
      <strong style="color: #27AE60;">ADC (12-bit)</strong><br>
      <code style="font-size: 12px; white-space: normal; overflow-wrap: anywhere; display: block; line-height: 1.5;">ADC1: GPIO32-39<br>ADC2: GPIO0,2,4,12-15,25-27</code><br>
      <small style="font-size: 10px; color: #7F8C8D;">ADC2 unavailable when Wi-Fi active</small>
    </div>

    <div style="background: white; padding: 12px; border-radius: 8px; border-left: 4px solid #3498DB; min-width: 0;">
      <strong style="color: #3498DB;">DAC</strong><br>
      <code style="font-size: 12px; white-space: normal; overflow-wrap: anywhere; display: block; line-height: 1.5;">GPIO25 (DAC1), GPIO26 (DAC2)</code>
    </div>

    <div style="background: white; padding: 12px; border-radius: 8px; border-left: 4px solid #9B59B6; min-width: 0;">
      <strong style="color: #9B59B6;">I2C (default)</strong><br>
      <code style="font-size: 12px; white-space: normal; overflow-wrap: anywhere; display: block; line-height: 1.5;">SDA: GPIO21, SCL: GPIO22</code>
    </div>

    <div style="background: white; padding: 12px; border-radius: 8px; border-left: 4px solid #F39C12; min-width: 0;">
      <strong style="color: #F39C12;">SPI (default)</strong><br>
      <code style="font-size: 12px; white-space: normal; overflow-wrap: anywhere; display: block; line-height: 1.5;">MOSI:23, MISO:19, CLK:18, CS:5</code>
    </div>

    <div style="background: white; padding: 12px; border-radius: 8px; border-left: 4px solid #16A085; min-width: 0;">
      <strong style="color: #16A085;">UART</strong><br>
      <code style="font-size: 12px; white-space: normal; overflow-wrap: anywhere; display: block; line-height: 1.5;">UART0: TX1, RX3<br>UART2: TX17, RX16</code>
    </div>

    <div style="background: white; padding: 12px; border-radius: 8px; border-left: 4px solid #E67E22; min-width: 0;">
      <strong style="color: #E67E22;">Touch</strong><br>
      <code style="font-size: 12px; white-space: normal; overflow-wrap: anywhere; display: block; line-height: 1.5;">GPIO0,2,4,12,13,14,15,27,32,33</code>
    </div>

    <div style="background: white; padding: 12px; border-radius: 8px; border-left: 4px solid #7F8C8D; min-width: 0;">
      <strong style="color: #7F8C8D;">Strapping (avoid)</strong><br>
      <code style="font-size: 12px; white-space: normal; overflow-wrap: anywhere; display: block; line-height: 1.5;">GPIO0,2,5,12,15 (boot mode)</code>
    </div>
  </div>

  <div style="margin-top: 15px; padding: 10px; background: #FEF5E7; border-radius: 6px; font-size: 13px;">
    <strong>Note:</strong> GPIO34-39 are input-only (no internal pull-up/pull-down).
  </div>
</div>
`

20.7 Common Patterns

20.7.1 Sensor Reading Pattern

# Pseudo-code for robust sensor reading
def read_sensor_with_retry(sensor, max_retries=3):
    for attempt in range(max_retries):
        try:
            value = sensor.read()
            if is_valid(value):
                return value
        except SensorError:
            time.sleep(0.1 * (2 ** attempt))  # Exponential backoff
    return None  # Or raise exception

# Moving average filter
class MovingAverage:
    def __init__(self, window=10):
        self.window = window
        self.values = []

    def add(self, value):
        self.values.append(value)
        if len(self.values) > self.window:
            self.values.pop(0)
        return sum(self.values) / len(self.values)

20.7.2 MQTT Connection Pattern

# Robust MQTT connection with reconnection
def connect_mqtt(client, broker, port=1883):
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            client.subscribe("device/+/command")
        else:
            print(f"Connection failed: {rc}")

    def on_disconnect(client, userdata, rc):
        while True:
            try:
                client.reconnect()
                break
            except:
                time.sleep(5)

    client.on_connect = on_connect
    client.on_disconnect = on_disconnect
    client.connect(broker, port, keepalive=60)

20.7.3 Deep Sleep Pattern

# ESP32 deep sleep with wake sources
import machine
import esp32

def enter_deep_sleep(seconds):
    # Configure wake sources
    esp32.wake_on_ext0(pin=machine.Pin(0), level=esp32.WAKEUP_ALL_LOW)

    # Set timer wake
    machine.deepsleep(seconds * 1000)

# Check wake reason
wake_reason = machine.wake_reason()
if wake_reason == machine.PIN_WAKE:
    handle_button_press()
elif wake_reason == machine.TIMER_WAKE:
    send_sensor_data()

20.8 Conversion Tables

Show code
html`
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin: 20px 0;">

  <div style="background: #f8f9fa; padding: 15px; border-radius: 8px;">
    <h4 style="margin-top: 0; color: #2C3E50;">dBm to mW</h4>
    <table style="width: 100%; font-size: 13px;">
      <tr><td>-20 dBm</td><td>0.01 mW</td></tr>
      <tr><td>-10 dBm</td><td>0.1 mW</td></tr>
      <tr><td>0 dBm</td><td>1 mW</td></tr>
      <tr><td>10 dBm</td><td>10 mW</td></tr>
      <tr><td>20 dBm</td><td>100 mW</td></tr>
      <tr><td>30 dBm</td><td>1000 mW = 1W</td></tr>
    </table>
    <div style="font-size: 11px; color: #666; margin-top: 10px;">
      mW = 10^(dBm/10)
    </div>
  </div>

  <div style="background: #f8f9fa; padding: 15px; border-radius: 8px;">
    <h4 style="margin-top: 0; color: #2C3E50;">Time Units</h4>
    <table style="width: 100%; font-size: 13px;">
      <tr><td>1 ms</td><td>0.001 s</td></tr>
      <tr><td>1 us</td><td>0.000001 s</td></tr>
      <tr><td>1 MHz</td><td>1,000,000 Hz</td></tr>
      <tr><td>1 kbps</td><td>1,000 bits/s</td></tr>
      <tr><td>1 Mbps</td><td>1,000,000 bits/s</td></tr>
    </table>
  </div>

  <div style="background: #f8f9fa; padding: 15px; border-radius: 8px;">
    <h4 style="margin-top: 0; color: #2C3E50;">Data Sizes</h4>
    <table style="width: 100%; font-size: 13px;">
      <tr><td>1 byte</td><td>8 bits</td></tr>
      <tr><td>1 KB</td><td>1,024 bytes</td></tr>
      <tr><td>1 MB</td><td>1,024 KB</td></tr>
      <tr><td>uint8</td><td>0-255</td></tr>
      <tr><td>int16</td><td>-32,768 to 32,767</td></tr>
      <tr><td>uint32</td><td>0 to 4,294,967,295</td></tr>
    </table>
  </div>

</div>
`
Worked Example: Using the ESP32 Pin-Out Reference for a Project

Scenario: You need to connect a DHT22 temperature sensor, an I2C OLED display, and monitor battery voltage on an ESP32.

Step 1: Identify Required Interfaces

  • DHT22: 1-wire digital protocol (needs any GPIO)
  • OLED: I2C interface (needs SDA + SCL)
  • Battery voltage: Analog input (needs ADC)

Step 2: Consult Pin-Out Reference

  • I2C (default): SDA=GPIO21, SCL=GPIO22
    • Decision: Use default I2C pins for OLED (no conflicts, easier debugging)
  • ADC (12-bit): GPIO32-39 (ADC1), GPIO0,2,4,12-15,25-27 (ADC2)
    • Note: ADC2 unavailable when Wi-Fi active
    • Decision: Use GPIO34 (ADC1_6) for battery voltage - always available
  • DHT22 data pin: Needs any free GPIO
    • Avoid: GPIO0,2,5,12,15 (strapping pins affect boot)
    • Avoid: GPIO34-39 (input-only, can’t use internal pullup)
    • Decision: Use GPIO4 (safe, not strapping, has pullup capability)

Step 3: Validate No Conflicts

  • GPIO4 (DHT22): Available, not used by I2C or ADC
  • GPIO21/22 (OLED I2C): Default I2C, no conflicts
  • GPIO34 (battery ADC): ADC1, works with Wi-Fi enabled

Step 4: Reference Formulas for ADC

  • From formula card: ADC Resolution = Vref / 2^bits
  • ESP32: 12-bit ADC, 3.3V reference
  • Step size: 3.3V / 4096 = 0.8mV per step
  • For 0-5V battery (using voltage divider): Divider ratio = 5V/3.3V = 1.52
    • Use 10kΩ and 15kΩ resistors: (15kΩ/(10kΩ+15kΩ)) × 5V = 3V at GPIO34

Step 5: Code Pattern from Reference

# From Moving Average Pattern (reference card)
battery_filter = MovingAverage(window=10)

# From Sensor Reading Pattern (reference card)
def read_dht22_with_retry():
    for attempt in range(3):
        try:
            temp, humidity = dht.read()
            if temp > -40 and temp < 80:  # Valid range
                return temp, humidity
        except:
            time.sleep(0.1 * (2 ** attempt))
    return None, None

Result: Complete wiring plan and code skeleton in 5 minutes by referencing the Quick Reference Cards instead of searching through 4 different chapter pages and datasheets.

Time Saved: Without reference cards: 20-30 minutes (find I2C chapter, find ADC chapter, look up strapping pins, search for code patterns). With reference cards: 5 minutes (scan one page, make decisions).


Match Protocol Parameters to Their Values

Order: Using Reference Cards During Development

Place these steps in the correct order for effective reference card usage.

Key Takeaway

Keep these reference cards handy during development and lab work. The key numbers (CR2032 = 220mAh, LoRa urban range = 2-5km, BLE range = 10-30m, CoAP header = 4 bytes) and protocol comparison tables enable quick design decisions without searching through full chapters.

Concept Relationships: Quick Reference Design Patterns
  • MQTT QoS Levels -> CoAP Message Types: Both provide reliability tiering. QoS 0/1/2 maps loosely to CoAP NON/CON/ACK patterns.
  • ESP32 Pin Configuration -> Power Budget Calculator: Pin selection affects current draw. ADC2 pins become unavailable during Wi-Fi.
  • LoRaWAN SF Selection -> Battery Life Formulas: Higher spreading factors increase airtime, directly impacting duty cycle limits.

Cross-module connection: Protocol Comparison (CoAP vs MQTT) - Compare protocol trade-offs using the same parameters listed on these cards

20.9 See Also

  • Code Snippet Library — Copy-paste implementation examples for the protocols and patterns shown in these reference cards
  • Simulations Hub — Interactive tools to validate link budget, battery life, and ADC formulas shown here
  • Troubleshooting Flowchart — Diagnostic trees that reference these cards for debugging MQTT, Wi-Fi, and sensor issues
  • Protocol Selector Wizard — Decision tool to choose between MQTT, CoAP, BLE, and LoRaWAN based on your requirements
  • IoT Games Hub — Reinforce quick-recall numbers through short challenge loops

Common Pitfalls

1. Creating Reference Cards From Memory Before Learning the Concepts

Writing personal reference cards before adequately understanding the underlying concepts embeds misconceptions in a convenient format. Study the full chapter material first, verify understanding through quiz performance, then create reference cards summarizing the correctly understood concepts.

2. Referencing Cards During Practice Instead of Testing Recall

Using reference cards as a crutch during practice problems prevents development of the working memory retrieval needed for on-the-job application. During practice, attempt problems without references first — consult cards only to verify your answer or when genuinely stuck, not before attempting recall.

3. Outdated Cards After Technology Updates

IoT technology parameters (protocol specs, hardware capabilities, cloud pricing) change frequently. Reference cards created during learning become outdated within 12-24 months. Review and update key reference cards annually, particularly for protocol specifications and hardware performance figures.

Knowledge Check

20.10 What’s Next

If you want to… Read this
Access code examples for common IoT tasks IoT Code Snippet Library
Test your knowledge against quick reference content Quiz Navigator
Build deeper understanding of referenced concepts Interactive Concept Navigator
Apply reference knowledge in hands-on labs Hands-On Labs Hub

20.11 Related Resources

  • Tool Discovery Hub - Find interactive tools
  • Glossary - Full term definitions
  • Protocol Comparison (CoAP vs MQTT) - Compare protocols
  • Power Budget Calculator - Calculate battery life
  • Wireless Range Calculator - Link budget analysis
  • IoT Games Hub - Challenge-based retention for quick-reference knowledge

Previous Current Next
Code Snippet Library Quick Reference Cards MVU Quick Reference
Label the Diagram

19  Discussion Prompts Hub
21  IoT Code Snippet Library