<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jay Lee</title>
    <description>The latest articles on DEV Community by Jay Lee (@jay_lee_0b8c51c411af400ee).</description>
    <link>https://dev.to/jay_lee_0b8c51c411af400ee</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3412615%2Fcb9eeee6-93be-4b19-9bdf-9095187a3030.png</url>
      <title>DEV Community: Jay Lee</title>
      <link>https://dev.to/jay_lee_0b8c51c411af400ee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jay_lee_0b8c51c411af400ee"/>
    <language>en</language>
    <item>
      <title>Integrating Web3 with IoT: Project Snowman’s New Blockchain-Powered CO Capture System</title>
      <dc:creator>Jay Lee</dc:creator>
      <pubDate>Mon, 11 Aug 2025 21:21:43 +0000</pubDate>
      <link>https://dev.to/jay_lee_0b8c51c411af400ee/integrating-web3-with-iot-project-snowmans-new-blockchain-powered-co2-capture-system-541h</link>
      <guid>https://dev.to/jay_lee_0b8c51c411af400ee/integrating-web3-with-iot-project-snowmans-new-blockchain-powered-co2-capture-system-541h</guid>
      <description>&lt;p&gt;Project Snowman is an IoT platform that measures and verifies CO₂ capture in real time.&lt;br&gt;
Our devices log environmental impact directly from the source — but until now, the data stayed in private databases.&lt;/p&gt;

&lt;p&gt;The problem? Trust.&lt;br&gt;
How can anyone verify that the numbers are accurate without relying solely on us?&lt;/p&gt;

&lt;p&gt;Why We’re Bringing Web3 Into the Loop&lt;br&gt;
Web3 solves this with public, immutable records.&lt;br&gt;
By recording capture events on-chain, we make every kilogram of CO₂ captured:&lt;/p&gt;

&lt;p&gt;Verifiable – Anyone can confirm the data against on-chain proofs.&lt;/p&gt;

&lt;p&gt;Immutable – No edits, no deletions, no tampering.&lt;/p&gt;

&lt;p&gt;Auditable – Third parties can run their own checks.&lt;/p&gt;

&lt;p&gt;This means Snowman’s environmental impact data now becomes part of a global, transparent ledger.&lt;/p&gt;

&lt;p&gt;The New Snowman Flow&lt;br&gt;
IoT Sensors measure CO₂ levels and capture rates.&lt;/p&gt;

&lt;p&gt;Data Processing happens in the Snowman app — validating, aggregating, and preparing proofs.&lt;/p&gt;

&lt;p&gt;Blockchain Proofs store hashes (Merkle roots) of the data for immutability.&lt;/p&gt;

&lt;p&gt;Snow Credits (ERC-20) are minted as loyalty-style rewards for verified impact.&lt;/p&gt;

&lt;p&gt;Achievement Badges (ERC-1155 NFTs) mark milestones and unlock perks.&lt;/p&gt;

&lt;p&gt;In-App Swap lets users exchange Snow Credits for other assets without leaving the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

contract SnowCredits is ERC20, AccessControl {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    constructor(address admin) ERC20("Snow Credits", "SNOW") {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(MINTER_ROLE, admin);
    }

    function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
        _mint(to, amount);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;`// SPDX-License-Identifier: MIT&lt;br&gt;
pragma solidity ^0.8.24;&lt;/p&gt;

&lt;p&gt;import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";&lt;br&gt;
import "@openzeppelin/contracts/access/AccessControl.sol";&lt;br&gt;
import "@openzeppelin/contracts/interfaces/IERC2981.sol";&lt;/p&gt;

&lt;p&gt;contract SnowBadges is ERC1155, AccessControl, IERC2981 {&lt;br&gt;
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");&lt;br&gt;
    address public royaltyReceiver;&lt;br&gt;
    uint96 public royaltyBps = 500; // 5%&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor(address admin, string memory baseURI) ERC1155(baseURI) {
    _grantRole(DEFAULT_ADMIN_ROLE, admin);
    _grantRole(MINTER_ROLE, admin);
    royaltyReceiver = admin;
}

function mint(address to, uint256 id, uint256 qty)
    external
    onlyRole(MINTER_ROLE)
{
    _mint(to, id, qty, "");
}

// ---- Optional soulbound guard ----
// uncomment to disable transfers between users
// function _beforeTokenTransfer(
//   address op, address from, address to, uint256[] memory ids,
//   uint256[] memory amts, bytes memory data
// ) internal override {
//   if (from != address(0) &amp;amp;&amp;amp; to != address(0)) revert("Soulbound");
//   super._beforeTokenTransfer(op, from, to, ids, amts, data);
// }

// ---- EIP-2981 royalties ----
function royaltyInfo(uint256, uint256 salePrice)
    external
    view
    returns (address, uint256)
{
    return (royaltyReceiver, (salePrice * royaltyBps) / 10_000);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
Technical Notes&lt;br&gt;
Tokens:&lt;/p&gt;

&lt;p&gt;Snow Credits → ERC-20 with MINTER_ROLE controlled by an admin wallet.&lt;/p&gt;

&lt;p&gt;Snow Badges → ERC-1155, optionally soulbound for certain tiers.&lt;/p&gt;

&lt;p&gt;Data Integrity:&lt;/p&gt;

&lt;p&gt;Raw telemetry stored off-chain (database/IPFS).&lt;/p&gt;

&lt;p&gt;Merkle root written to the blockchain for verification.&lt;/p&gt;

&lt;p&gt;Wallet Integration:&lt;/p&gt;

&lt;p&gt;Uses wagmi + RainbowKit for a quick connect flow.&lt;/p&gt;

&lt;p&gt;Smart wallets (ERC-4337) under consideration for gasless claims.&lt;/p&gt;

&lt;p&gt;Swap Function:&lt;/p&gt;

&lt;p&gt;Uniswap v3 or 0x aggregator integrated via in-app UI.&lt;/p&gt;

&lt;p&gt;Snow Credits paired against USDC or WETH on Polygon/Base for low fees.&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;br&gt;
// wagmi v2 + viem&lt;br&gt;
import { useWriteContract } from 'wagmi'&lt;br&gt;
import snowCreditsAbi from './abi/SnowCredits.json'&lt;br&gt;
import snowBadgesAbi from './abi/SnowBadges.json'&lt;/p&gt;

&lt;p&gt;const SNOW_CREDITS = '0xYourSnowCredits';&lt;br&gt;
const SNOW_BADGES  = '0xYourSnowBadges';&lt;/p&gt;

&lt;p&gt;export function AdminActions({ user, credits, badgeId }:{&lt;br&gt;
  user: &lt;code&gt;0x${string}&lt;/code&gt;, credits: string, badgeId: number&lt;br&gt;
}) {&lt;br&gt;
  const { writeContractAsync } = useWriteContract();&lt;/p&gt;

&lt;p&gt;const awardCredits = async () =&amp;gt; {&lt;br&gt;
    await writeContractAsync({&lt;br&gt;
      address: SNOW_CREDITS,&lt;br&gt;
      abi: snowCreditsAbi,&lt;br&gt;
      functionName: 'mint',&lt;br&gt;
      args: [user, BigInt(credits)] // credits are 18 decimals in the ABI&lt;br&gt;
    });&lt;br&gt;
  };&lt;/p&gt;

&lt;p&gt;const mintBadge = async () =&amp;gt; {&lt;br&gt;
    await writeContractAsync({&lt;br&gt;
      address: SNOW_BADGES,&lt;br&gt;
      abi: snowBadgesAbi,&lt;br&gt;
      functionName: 'mint',&lt;br&gt;
      args: [user, BigInt(badgeId), 1n]&lt;br&gt;
    });&lt;br&gt;
  };&lt;/p&gt;

&lt;p&gt;return (&lt;br&gt;
    &amp;lt;&amp;gt;&lt;br&gt;
      Award Credits&lt;br&gt;
      Mint Badge #{badgeId}&lt;br&gt;
    &amp;lt;/&amp;gt;&lt;br&gt;
  );&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
// Pseudocode (Node.js) – illustrate approach without revealing data model&lt;br&gt;
import { createHash } from 'crypto';&lt;br&gt;
// const cid = await ipfsAdd(JSON.stringify(redactedSummary))&lt;/p&gt;

&lt;p&gt;export function proofHash(jsonSummary: string) {&lt;br&gt;
  return createHash('sha256').update(jsonSummary).digest('hex');&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Later on-chain you would store: { periodId, wallet, cid, hash }&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`&lt;br&gt;
`&lt;/code&gt;&lt;br&gt;
Why It Matters for Developers&lt;br&gt;
This architecture is modular and chain-agnostic.&lt;br&gt;
You can replicate the model for any IoT → Proof → Reward flow, whether you’re measuring emissions, renewable generation, or supply chain events.&lt;/p&gt;

&lt;p&gt;The key takeaway: don’t put raw IoT data directly on-chain.&lt;br&gt;
Instead, store proofs (hashes) to keep transactions lightweight, private, and cost-effective.&lt;/p&gt;

&lt;p&gt;Next Steps for Project Snowman&lt;br&gt;
Phase 1 – On-chain proofs + wallet integration (in progress)&lt;/p&gt;

&lt;p&gt;Phase 2 – Snow Credits minting + badge reward system&lt;/p&gt;

&lt;p&gt;Phase 3 – Full in-app swap and expanded partner ecosystem&lt;/p&gt;

&lt;p&gt;If you’re building in IoT, blockchain, or climate tech — I’d love to connect and exchange ideas.&lt;/p&gt;

&lt;p&gt;💬 What’s your take on using NFTs and tokens for environmental incentives? Would love to hear from other builders in the comments.&lt;/p&gt;

&lt;h1&gt;
  
  
  IoT #Web3 #Blockchain #NFTs #DeFi #ClimateTech #ProjectSnowman
&lt;/h1&gt;

</description>
      <category>iot</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>nft</category>
    </item>
    <item>
      <title>How We Cut IoT Backend Calls by 85% with C++ and BLE Pairing on ESP32</title>
      <dc:creator>Jay Lee</dc:creator>
      <pubDate>Mon, 04 Aug 2025 17:52:49 +0000</pubDate>
      <link>https://dev.to/jay_lee_0b8c51c411af400ee/how-we-cut-iot-backend-calls-by-85-with-c-and-ble-pairing-on-esp32-389k</link>
      <guid>https://dev.to/jay_lee_0b8c51c411af400ee/how-we-cut-iot-backend-calls-by-85-with-c-and-ble-pairing-on-esp32-389k</guid>
      <description>&lt;h1&gt;
  
  
  ❄️ How We Cut IoT Backend Calls by 85% with C++ and BLE Pairing on ESP32
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Project Snowman&lt;/strong&gt; is an embedded IoT system built on an ESP32. Our goal?&lt;br&gt;&lt;br&gt;
Collect real-time environmental data, send it to the cloud, and display it on a live frontend —&lt;br&gt;&lt;br&gt;
all while minimizing backend strain and keeping config secure.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔧 Hardware &amp;amp; Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;ESP32&lt;/li&gt;
&lt;li&gt;DS18B20 temperature sensors&lt;/li&gt;
&lt;li&gt;C++ with PlatformIO&lt;/li&gt;
&lt;li&gt;BLE + Wi-Fi&lt;/li&gt;
&lt;li&gt;REST API (Render backend)&lt;/li&gt;
&lt;li&gt;React + Vite frontend (Netlify)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🧱 Modular C++ Architecture (S.O.L.I.D. Principles)
&lt;/h2&gt;

&lt;p&gt;We designed the firmware using modern object-oriented programming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SensorManager&lt;/code&gt; handles DS18B20 readings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WiFiManager&lt;/code&gt; connects to Wi-Fi and checks status&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BLEServerModule&lt;/code&gt; handles proximity-based setup&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;APIClient&lt;/code&gt; pushes data only when requested
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bleTriggeredReconnect&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bleReconnectTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WiFi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bleSSID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;blePassword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="n"&gt;bleServer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;stopAdvertising&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each class has a single responsibility — easy to debug, maintain, and scale.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔐 BLE Pairing Mode with Proximity Logic
&lt;/h2&gt;

&lt;p&gt;BLE is used for configuration. No insecure web portals.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BLE GATT server activates only during setup mode&lt;/li&gt;
&lt;li&gt;Accepts Wi-Fi credentials from a phone&lt;/li&gt;
&lt;li&gt;Reconnects automatically and turns off BLE afterward&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  ⚙️ Request-Only Backend API Flow
&lt;/h2&gt;

&lt;p&gt;Instead of pushing sensor data continuously, the ESP32 sends updates &lt;strong&gt;only when requested&lt;/strong&gt; by the frontend.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dropped backend calls from &lt;strong&gt;100+ per hour&lt;/strong&gt; ➝ &lt;strong&gt;~15&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Reduced bandwidth, power, and compute costs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/link-to-your-chart" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/link-to-your-chart" alt="Chart showing call reduction" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  💻 Frontend Integration (React + Vite)
&lt;/h2&gt;

&lt;p&gt;The frontend fetches sensor data and renders it in real-time using stat cards.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/data/latest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fast. Clean. Minimal load.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What We Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Event-driven IoT logic beats constant loop polling&lt;/li&gt;
&lt;li&gt;BLE provisioning improves security + UX&lt;/li&gt;
&lt;li&gt;PlatformIO and C++ OOP scale beautifully for embedded builds&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔜 What’s Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Audit logging for BLE pairing events&lt;/li&gt;
&lt;li&gt;Push BLE config via mobile app&lt;/li&gt;
&lt;li&gt;Real-world vehicle deployments&lt;/li&gt;
&lt;li&gt;Publishing full Medium article + case study&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Let me know what you're building — and if you're working on embedded systems or sustainable tech, let's connect!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags&lt;/strong&gt;: &lt;code&gt;#esp32&lt;/code&gt; &lt;code&gt;#c++&lt;/code&gt; &lt;code&gt;#iot&lt;/code&gt; &lt;code&gt;#ble&lt;/code&gt; &lt;code&gt;#embedded&lt;/code&gt; &lt;code&gt;#platformio&lt;/code&gt;&lt;/p&gt;

</description>
      <category>esp32</category>
      <category>iot</category>
      <category>ble</category>
      <category>embedded</category>
    </item>
  </channel>
</rss>
