diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5356bba
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+# Smart Vision IT Solution IoT App
+
+This repository contains a lightweight web-based IoT dashboard for **Smart Vision IT Solution**.
+The app is branded for the business and prepared to connect with an **ESP RainMaker** backend so users can control:
+
+- Living room light
+- Bedroom light
+- Main hall fan
+
+## Features
+
+- Smart Vision IT Solution branding and contact details
+- ESP RainMaker connection form for base URL and access token
+- Device cards for light switches and fan power/speed control
+- Activity log showing local updates and backend sync events
+- Responsive glassmorphism UI for desktop and mobile
+
+## Contact
+
+- Phone: [9818429568](tel:9818429568)
+- Email: [svitsolution@outlook.com](mailto:svitsolution@outlook.com)
+
+## Run locally
+
+Because the project is a static web app, you can run it with any static server. For example:
+
+```bash
+python3 -m http.server 4173
+```
+
+Then open `http://localhost:4173` in your browser.
+
+## ESP RainMaker integration note
+
+The `script.js` file includes a `RainMakerClient` abstraction that is ready for wiring into your actual ESP RainMaker API flow. Replace the simulated `connect()` and `updateDevice()` methods with your production API requests and authentication handling when your backend credentials and node schema are available.
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..271b337
--- /dev/null
+++ b/index.html
@@ -0,0 +1,182 @@
+
+
+
+
+
+ Smart Vision IT Solution
+
+
+
+
+
+
+
+
+
+
+
ESP RainMaker Enabled IoT App
+
Smart Vision IT Solution
+
+ Manage connected lights and fan devices from one polished control panel backed by
+ an ESP RainMaker-ready API layer.
+
+
+
+
+
RainMaker Cloud Ready
+
Remote automation, scenes, and live device updates.
+
+ Built to connect your switch lights and fan controllers with ESP RainMaker services,
+ status sync, and command delivery.
+
+
+ Light switch controls with instant feedback
+ Fan on/off and speed regulation
+ Prepared for RainMaker authentication token usage
+
+
+
+
+
+
+
+
+
Backend
+
ESP RainMaker Connection
+
+
+
+ RainMaker base URL
+
+
+
+ Access token
+
+
+ Connect backend
+
+
+ Add your ESP RainMaker URL and token to send commands to devices.
+
+
+
+
+
+
Highlights
+
App Capabilities
+
+
+
+ 02
+ Switch light controls
+
+
+ 01
+ Fan controller with speed slider
+
+
+ 24/7
+ Cloud-ready monitoring experience
+
+
+ 100%
+ Branding customized for Smart Vision IT Solution
+
+
+
+
+
+
+
+
Controls
+
Rooms & Devices
+
Tap the toggles below to switch lights and control the smart fan.
+
+
+
+
+
+
+
+
Activity
+
Recent Commands
+
+
+ Dashboard initialized. Waiting for ESP RainMaker connection.
+
+
+
+
+
+
+
+
+
+
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..e588da6
--- /dev/null
+++ b/script.js
@@ -0,0 +1,133 @@
+const state = {
+ connected: false,
+ baseUrl: 'https://api.rainmaker.espressif.com',
+ authToken: '',
+ devices: {
+ 'light-living-room': { type: 'light', power: false },
+ 'light-bedroom': { type: 'light', power: false },
+ 'fan-main-hall': { type: 'fan', power: false, speed: 3 },
+ },
+};
+
+const activityLog = document.getElementById('activityLog');
+const connectionMessage = document.getElementById('connectionMessage');
+const baseUrlInput = document.getElementById('baseUrl');
+const authTokenInput = document.getElementById('authToken');
+const connectBtn = document.getElementById('connectBtn');
+const fanSpeedInput = document.getElementById('fanSpeed');
+const fanSpeedValue = document.getElementById('fanSpeedValue');
+const toggles = document.querySelectorAll('.device-toggle');
+
+class RainMakerClient {
+ constructor() {
+ this.baseUrl = state.baseUrl;
+ this.authToken = state.authToken;
+ }
+
+ configure({ baseUrl, authToken }) {
+ this.baseUrl = baseUrl;
+ this.authToken = authToken;
+ }
+
+ async connect() {
+ if (!this.authToken.trim()) {
+ throw new Error('An ESP RainMaker access token is required.');
+ }
+
+ await this.simulateNetwork();
+ return {
+ ok: true,
+ message: `Connected to ${this.baseUrl}`,
+ };
+ }
+
+ async updateDevice(deviceId, payload) {
+ await this.simulateNetwork();
+
+ return {
+ ok: true,
+ endpoint: `${this.baseUrl}/v1/user/nodes/params`,
+ deviceId,
+ payload,
+ };
+ }
+
+ simulateNetwork() {
+ return new Promise((resolve) => {
+ window.setTimeout(resolve, 320);
+ });
+ }
+}
+
+const rainMakerClient = new RainMakerClient();
+
+const appendLog = (message) => {
+ const entry = document.createElement('li');
+ entry.textContent = `${new Date().toLocaleTimeString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ })} — ${message}`;
+ activityLog.prepend(entry);
+};
+
+const syncFormState = () => {
+ state.baseUrl = baseUrlInput.value.trim() || 'https://api.rainmaker.espressif.com';
+ state.authToken = authTokenInput.value.trim();
+ rainMakerClient.configure({
+ baseUrl: state.baseUrl,
+ authToken: state.authToken,
+ });
+};
+
+connectBtn.addEventListener('click', async () => {
+ syncFormState();
+ connectBtn.disabled = true;
+ connectBtn.textContent = 'Connecting...';
+
+ try {
+ const result = await rainMakerClient.connect();
+ state.connected = true;
+ connectionMessage.textContent = `${result.message}. Ready to control lights and fan.`;
+ appendLog('ESP RainMaker backend connected successfully.');
+ } catch (error) {
+ state.connected = false;
+ connectionMessage.textContent = error.message;
+ appendLog(`Connection failed: ${error.message}`);
+ } finally {
+ connectBtn.disabled = false;
+ connectBtn.textContent = 'Connect backend';
+ }
+});
+
+const sendDeviceUpdate = async (deviceId, payload) => {
+ state.devices[deviceId] = {
+ ...state.devices[deviceId],
+ ...payload,
+ };
+
+ if (!state.connected) {
+ appendLog(
+ `Updated ${deviceId} locally. Connect to ESP RainMaker to send the command to the cloud.`,
+ );
+ return;
+ }
+
+ const result = await rainMakerClient.updateDevice(deviceId, payload);
+ appendLog(`Synced ${result.deviceId} to ${result.endpoint} with ${JSON.stringify(payload)}.`);
+};
+
+toggles.forEach((toggle) => {
+ toggle.addEventListener('change', async (event) => {
+ const { deviceId } = event.target.dataset;
+ const power = event.target.checked;
+ await sendDeviceUpdate(deviceId, { power });
+ });
+});
+
+fanSpeedInput.addEventListener('input', async (event) => {
+ const speed = Number(event.target.value);
+ fanSpeedValue.textContent = String(speed);
+ await sendDeviceUpdate('fan-main-hall', { speed });
+});
+
+appendLog('Smart Vision IT Solution dashboard is ready.');
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..36822c3
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,389 @@
+:root {
+ color-scheme: dark;
+ --bg: #09111f;
+ --panel: rgba(12, 24, 46, 0.78);
+ --panel-border: rgba(134, 197, 255, 0.18);
+ --accent: #53b3ff;
+ --accent-strong: #7c5cff;
+ --text: #eff5ff;
+ --muted: #adc2e0;
+ --success: #49dcb1;
+ --shadow: 0 18px 40px rgba(0, 0, 0, 0.28);
+}
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ margin: 0;
+ min-height: 100vh;
+ font-family: 'Inter', sans-serif;
+ background:
+ radial-gradient(circle at top left, rgba(124, 92, 255, 0.25), transparent 28%),
+ radial-gradient(circle at top right, rgba(83, 179, 255, 0.22), transparent 24%),
+ linear-gradient(135deg, #040810 0%, #09111f 50%, #0a1730 100%);
+ color: var(--text);
+}
+
+body::before {
+ content: '';
+ position: fixed;
+ inset: 0;
+ background-image: linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
+ background-size: 42px 42px;
+ pointer-events: none;
+}
+
+.page-shell {
+ width: min(1180px, calc(100% - 32px));
+ margin: 0 auto;
+ padding: 32px 0 48px;
+}
+
+.card {
+ background: var(--panel);
+ border: 1px solid var(--panel-border);
+ box-shadow: var(--shadow);
+ backdrop-filter: blur(18px);
+ border-radius: 28px;
+}
+
+.hero {
+ display: grid;
+ grid-template-columns: 1.25fr 0.95fr;
+ gap: 24px;
+ padding: 32px;
+}
+
+.eyebrow {
+ margin: 0 0 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ font-size: 0.75rem;
+ font-weight: 700;
+ color: var(--accent);
+}
+
+.hero h1,
+.section-heading h2,
+.status-panel h2,
+.device-card h3 {
+ margin: 0;
+}
+
+.hero h1 {
+ font-size: clamp(2.4rem, 4vw, 4rem);
+ line-height: 1.05;
+ max-width: 11ch;
+}
+
+.hero-copy,
+.status-panel p,
+.section-heading p,
+.device-card p,
+.helper-text,
+.activity-log li,
+.contact-grid a {
+ color: var(--muted);
+}
+
+.hero-copy {
+ max-width: 60ch;
+ font-size: 1.05rem;
+ line-height: 1.7;
+ margin: 18px 0 28px;
+}
+
+.hero-actions,
+.contact-grid,
+.connection-grid,
+.device-grid,
+.stats-grid {
+ display: grid;
+ gap: 16px;
+}
+
+.hero-actions {
+ grid-template-columns: repeat(2, minmax(0, max-content));
+}
+
+.button {
+ appearance: none;
+ border: 0;
+ border-radius: 999px;
+ padding: 14px 22px;
+ font-weight: 700;
+ cursor: pointer;
+ text-decoration: none;
+ transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
+}
+
+.button:hover {
+ transform: translateY(-1px);
+}
+
+.button.primary {
+ background: linear-gradient(135deg, var(--accent), var(--accent-strong));
+ color: white;
+ box-shadow: 0 10px 24px rgba(83, 179, 255, 0.24);
+}
+
+.button.secondary {
+ background: rgba(255, 255, 255, 0.06);
+ color: var(--text);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+}
+
+.status-panel {
+ padding: 28px;
+ background: linear-gradient(180deg, rgba(83, 179, 255, 0.12), rgba(124, 92, 255, 0.12));
+ border-radius: 24px;
+ border: 1px solid rgba(255, 255, 255, 0.09);
+}
+
+.status-chip {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ border-radius: 999px;
+ padding: 8px 12px;
+ font-weight: 700;
+ font-size: 0.85rem;
+}
+
+.status-chip.live {
+ background: rgba(73, 220, 177, 0.14);
+ color: #92ffe0;
+}
+
+.status-panel ul {
+ padding-left: 18px;
+ margin: 18px 0 0;
+ color: var(--muted);
+ line-height: 1.8;
+}
+
+main {
+ display: grid;
+ gap: 24px;
+ margin-top: 24px;
+}
+
+.connection-grid {
+ grid-template-columns: 1.05fr 0.95fr;
+}
+
+.connection-card,
+.insights-card,
+.activity-card,
+.contact-card {
+ padding: 28px;
+}
+
+.connection-form {
+ display: grid;
+ gap: 14px;
+}
+
+label {
+ display: grid;
+ gap: 8px;
+ font-size: 0.95rem;
+ font-weight: 600;
+}
+
+input[type='url'],
+input[type='password'] {
+ width: 100%;
+ border-radius: 16px;
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ background: rgba(3, 10, 22, 0.64);
+ color: var(--text);
+ padding: 14px 16px;
+ font: inherit;
+}
+
+.helper-text {
+ margin-bottom: 0;
+}
+
+.stats-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ margin-top: 16px;
+}
+
+.stats-grid div {
+ padding: 20px;
+ border-radius: 22px;
+ background: rgba(255, 255, 255, 0.04);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+}
+
+.stats-grid strong {
+ display: block;
+ font-size: 1.8rem;
+ margin-bottom: 8px;
+}
+
+.controls-section {
+ display: grid;
+ gap: 20px;
+}
+
+.device-grid {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+
+.device-card {
+ padding: 24px;
+ display: grid;
+ gap: 18px;
+}
+
+.device-meta {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+}
+
+.device-icon {
+ width: 56px;
+ height: 56px;
+ display: inline-grid;
+ place-items: center;
+ border-radius: 18px;
+ background: rgba(255, 255, 255, 0.08);
+ font-size: 1.6rem;
+}
+
+.switch-row,
+.range-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+}
+
+input[type='checkbox'] {
+ width: 56px;
+ height: 28px;
+ appearance: none;
+ background: rgba(255, 255, 255, 0.16);
+ border-radius: 999px;
+ position: relative;
+ transition: background 0.2s ease;
+ cursor: pointer;
+}
+
+input[type='checkbox']::after {
+ content: '';
+ position: absolute;
+ top: 3px;
+ left: 4px;
+ width: 22px;
+ height: 22px;
+ border-radius: 50%;
+ background: white;
+ transition: transform 0.2s ease;
+}
+
+input[type='checkbox']:checked {
+ background: linear-gradient(135deg, var(--accent), var(--accent-strong));
+}
+
+input[type='checkbox']:checked::after {
+ transform: translateX(26px);
+}
+
+.range-row div {
+ min-width: 160px;
+ display: flex;
+ align-items: center;
+ gap: 14px;
+}
+
+input[type='range'] {
+ width: 100%;
+ accent-color: var(--accent);
+}
+
+.activity-log {
+ list-style: none;
+ padding: 0;
+ margin: 18px 0 0;
+ display: grid;
+ gap: 12px;
+}
+
+.activity-log li {
+ padding: 14px 16px;
+ border-radius: 16px;
+ background: rgba(255, 255, 255, 0.04);
+ border: 1px solid rgba(255, 255, 255, 0.06);
+}
+
+.contact-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ margin-top: 18px;
+}
+
+.contact-grid a {
+ text-decoration: none;
+ font-weight: 600;
+ padding: 18px 20px;
+ border-radius: 18px;
+ background: rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+}
+
+code {
+ font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
+ color: #a9f0ff;
+}
+
+@media (max-width: 960px) {
+ .hero,
+ .connection-grid,
+ .device-grid,
+ .contact-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+@media (max-width: 640px) {
+ .page-shell {
+ width: min(100% - 20px, 1180px);
+ padding-top: 20px;
+ }
+
+ .hero,
+ .connection-card,
+ .insights-card,
+ .activity-card,
+ .contact-card,
+ .device-card {
+ padding: 20px;
+ border-radius: 22px;
+ }
+
+ .hero-actions,
+ .stats-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .range-row,
+ .switch-row {
+ align-items: flex-start;
+ flex-direction: column;
+ }
+
+ .range-row div {
+ width: 100%;
+ }
+}