Chapterبەش 7 · Lectureوانە 7.2

Storing IoT Readings in the Cloudهەڵگرتنی خوێندنەوەکانی IoT لە هەوردا

A cloud back end for sensor readings with Supabase: a typed Postgres table (time, temperature, cover_open), the REST API that PostgREST makes for it, the 2026 rule that tables need explicit grants, publishable and secret keys, Row Level Security policies, a Nano ESP32 sketch that adds a row every minute and reads the reply code, dashboards with an hourly query and a chart, the phone app, and Firebase Firestore compared.

هەوری بۆ خوێندنەوەی بە Supabase: جۆرداکراوی Postgres (کات، پلەی گەرمی، ⁦cover_open⁩)، ئەو APIـیەی PostgREST بۆی دروست دەکات، یاسای ⁦2026⁩ کە مۆڵەتی ئاشکرایان دەوێت، و ، سیاسەتەکانی ، ⁦Nano ESP32⁩ کە هەموو خولەکێک ڕیزێک زیاد دەکات و کۆدی وەڵام دەخوێنێتەوە، بە کاتژمێری و ، ئەپی مۆبایل و بەراوردکردن لەگەڵ Firebase Firestore.

18 min read19 خولەک خوێندنەوە · 17 stepsهەنگاو

What you will learnچی فێر دەبیت

  • Design a typed table for sensor readings and create it with SQL.
  • Use the auto-generated REST API to insert and read rows.
  • Explain publishable and secret keys, grants and Row Level Security, and keep a device safe with them.
  • Send a reading from a Wi-Fi board over HTTPS and act on the reply code.
  • Show stored readings in a dashboard and an app, and compare Supabase with Firebase.
  • جۆرداکراو بۆ خوێندنەوەی دیزاین بکەیت و بە دروستی بکەیت.
  • APIـیە خۆکارەکە بۆ زیادکردن و خوێندنەوەی ڕیز بەکار بهێنیت.
  • و ، مۆڵەت و ڕوون بکەیتەوە و ئامێرێک پێیان بپارێزیت.
  • خوێندنەوەیەک لە بۆردێکی بە بنێریت و بەپێی کۆدی وەڵامەکە کار بکەیت.
  • خوێندنەوە هەڵگیراوەکان لە و ئەپێکدا پیشان بدەیت و Supabase لەگەڵ Firebase بەراورد بکەیت.

Where do the readings go?خوێندنەوەکان بۆ کوێ دەچن؟

A sensor that reports every minute makes 1,440 readings a day. To be useful they must be stored, searched and shown: “what was the temperature last night?”, “was the cover closed at sunset?”. That is the job of a back end in the cloud (the cloud model). Instead of building a server yourself, you can rent a Backend-as-a-Service that gives you a database, an API and sign-in ready-made (BaaS).

کە هەموو خولەکێک دەنێرێت ڕۆژانە ⁦1,440⁩ خوێندنەوە دروست دەکات. بۆ ئەوەی بەسوود بن دەبێت هەڵبگیرێن، بگەڕێنرێن و پیشان بدرێن: «دوێنێ شەو پلەی گەرمی چەند بوو؟»، «لە کاتی ئاوابوونی خۆردا بەرگەکە داخرابوو؟». ئەمە ئەرکی لە هەوردا (مۆدێلی هەور). لە جیاتی ئەوەی خۆت دروست بکەیت، دەتوانیت بەکرێ بگریت کە ، API و چوونەژوورەوەت بە ئامادەیی دەداتێ (BaaS).

This lesson uses Supabase, the service named in this course’s bird-cage project: every Supabase project is a full Postgres database with an API made for you. The path is: board → Wi-Fi → HTTPS request → a table → apps and dashboards. Sending over HTTP and JSON was taught in Sending IoT data.

ئەم وانەیە Supabase بەکار دەهێنێت، ئەو خزمەتگوزارییەی لە پرۆژەی قەفەزی باڵندەی ئەم خولەدا ناوی هاتووە: هەموو پرۆژەیەکی Supabase تەواوی Postgresـە لەگەڵ APIـیەک کە بۆت دروست کراوە. ڕێڕەوەکە ئەمەیە: بۆرد ← ← ← ← ئەپ و . ناردن بە و لە ناردنی دراوەی IoT فێر کرا.

A Nano ESP32 board with a DHT11 and a switch sends through a Wi-Fi router and the internet an HTTPS POST with JSON to a Supabase project, which contains a REST API made for you at /rest/v1/readings and a Postgres table called readings. From the project, a phone app and a dashboard read the data with GET. Four steps: 1 read the sensors; 2 send one row as JSON over HTTPS; 3 the API checks the key and the rules, then adds the row; 4 apps read the table.بۆردێکی Nano ESP32 لەگەڵ DHT11 و سویچێکی سنوور لە ڕێگەی ڕێدۆزی وای‌فای و ئینتەرنێتەوە POSTـێکی HTTPS بە JSON دەنێرێت بۆ پرۆژەیەکی Supabase، کە REST APIـیەکی بۆت دروستکراو لە /rest/v1/readings و خشتەیەکی Postgres بە ناوی readings تێدایە. لە پرۆژەکەوە ئەپێکی مۆبایل و داشبۆردێک بە GET دراوەکە دەخوێننەوە. چوار هەنگاو: 1 هەستەوەرەکان دەخوێنێتەوە؛ 2 ڕیزێک وەک JSON بە HTTPS دەنێرێت؛ 3 API کلیلی APIـیەکە و یاساکان دەپشکنێت و پاشان ڕیزەکە زیاد دەکات؛ 4 ئەپەکان خشتەکە دەخوێننەوە.
One reading’s trip, from the cage to the phone.گەشتی یەک خوێندنەوە، لە قەفەزەکەوە بۆ مۆبایل.CêIT

Design the readings tableدیزاینی خشتەی خوێندنەوەکان

In a relational database, data lives in tables: each row (record) is one reading and each column (field) has a fixed data type (tables, rows and columns). The project stores two values per reading — the temperature (a decimal number, a double) and whether the cage cover is open (a Boolean) — so the table needs:

لە لە یە: هەر (ڕیز) یەک خوێندنەوەیە و هەر (ستوون) جێگیری هەیە (خشتە، ڕیز و ستوون). پرۆژەکە دوو نرخ بۆ هەر خوێندنەوەیەک هەڵدەگرێت — پلەی گەرمی (، double) و ئایا بەرگی قەفەزەکە کراوەیە () — بۆیە پێویستی بەمانەیە:

  • id — a number the database gives each row (the primary key).
  • created_at — a timestamp the database fills in itself; a small board has no reliable clock. Postgres timestamptz stores it in UTC, and the app shows Erbil time (UTC+3).
  • device — which board sent it, so several cages can share one table.
  • temperature — double precision (a double, also called float8).
  • cover_open — boolean: true or false.
  • id — ژمارەیەک کە دەیداتە هەر ڕیزێک ().
  • created_at — کە خۆی پڕی دەکاتەوە؛ بۆردێکی بچووک کاتژمێرێکی متمانەپێکراوی نییە. timestamptzـی Postgres بە UTC هەڵیدەگرێت و ئەپەکە کاتی هەولێر ⁦(UTC+3)⁩ پیشان دەدات.
  • device — کام بۆرد ناردوویەتی، بۆ ئەوەی چەند قەفەزێک یەک بەکار بهێنن.
  • temperature — double precision (double، کە پێی دەڵێن float8ـیش).
  • cover_open — boolean: true یان false.
A table called readings with five columns: id (bigint, identity), created_at (timestamptz), device (text), temperature (double precision) and cover_open (boolean). Four example rows from 2026-11-05 10:00 to 10:03, device cage-01, temperatures 24.5, 24.5, 24.3 and 24.1, cover_open true, true, true, false. Notes: columns are fixed and typed, so the database refuses a word where a number belongs; id and created_at are filled in by the database, and the board sends only the last three; one row a minute is 1,440 rows a day, about 525,600 a year.خشتەیەک بە ناوی readings و پێنج ستوون: id (bigint، خۆکار)، created_at (timestamptz)، device (دەق)، temperature (double precision) و cover_open (boolean). چوار ڕیزی نموونە لە 2026-11-05 10:00 تا 10:03، ئامێری cage-01، پلەی گەرمیی 24.5، 24.5، 24.3 و 24.1، cover_open: true، true، true، false. تێبینی: ستوونەکان جێگیر و جۆرداکراون، بۆیە بنکەدراوەکە وشەیەک لە شوێنی ژمارەدا ڕەت دەکاتەوە؛ id و created_at بنکەدراوەکە پڕیان دەکاتەوە و بۆردەکە تەنیا سێ دواییەکە دەنێرێت؛ ڕیزێک لە هەر خولەکێکدا دەکاتە 1,440 ڕیز لە ڕۆژێکدا، نزیکەی 525,600 لە ساڵێکدا.
One reading = one row, with typed columns.یەک خوێندنەوە = یەک ، بە جۆرداکراو.CêIT

Design the readings tableدیزاینی خشتەی خوێندنەوەکان

Creating the table in Supabaseدروستکردنی خشتەکە لە Supabaseـدا

You can click the table together in Supabase’s Table Editor, or paste this SQL into its SQL Editor (CREATE TABLE). It makes the table, switches on Row Level Security, and gives each kind of user only what it needs — the next screens explain the grants, the keys and the policies.

دەتوانیت لە Table Editorـی Supabaseـدا بە کرتە دروست بکەیت، یان ئەم لە SQL Editorـەکەیدا دابنێیت (CREATE TABLE). دروست دەکات، هەڵدەکات و بە هەر جۆرە بەکارهێنەرێک تەنیا ئەوە دەدات کە پێویستیەتی — پەڕەکانی داهاتوو مۆڵەتەکان، و سیاسەتەکان ڕوون دەکەنەوە.

The readings table with its rulesخشتەی خوێندنەوەکان لەگەڵ یاساکانیreadings.sqlSQLRuns in the databaseلە ناو بنکەدراوە کار دەکات
-- 1. The table: one row per reading
create table public.readings (
  id          bigint generated always as identity primary key,
  created_at  timestamptz not null default now(),
  device      text not null,
  temperature double precision not null check (temperature between -40 and 80),
  cover_open  boolean not null
);

-- 2. Switch on Row Level Security
alter table public.readings enable row level security;

-- 3. Boards (publishable key = role anon) may only add rows
grant insert on public.readings to anon;
create policy "boards can add readings"
  on public.readings for insert
  to anon
  with check (device = 'cage-01');

-- 4. Signed-in users of the app may read them
grant select on public.readings to authenticated;
create policy "signed-in users can read readings"
  on public.readings for select
  to authenticated
  using (true);
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 3

generated always as identity: the database numbers the rows itself.

generated always as identity: خۆی ژمارە دەداتە ڕیزەکان.

Lineدێڕی 4

default now() fills in the time of arrival.

default now() کاتی گەیشتن پڕ دەکاتەوە.

Lineدێڕی 6

A check refuses impossible values, such as 999 °C from a faulty sensor.

check نرخی نەگونجاو ڕەت دەکاتەوە، وەک ⁦999 °C⁩ لە تێکچووەوە.

Lineدێڕی 14-18

The board may only add rows, and only for its own device name.

بۆردەکە تەنیا دەتوانێت ڕیز زیاد بکات، ئەویش تەنیا بۆ ناوی ئامێرەکەی خۆی.

Lineدێڕی 21-25

Signed-in app users may read; nobody may change or delete rows through the API.

بەکارهێنەرانی چووەژوورەوەی ئەپ دەتوانن بخوێننەوە؛ هیچ کەس ناتوانێت لە ڕێگەی APIـیەوە ڕیز بگۆڕێت یان بسڕێتەوە.

A REST API made for youREST APIـیەک کە بۆت دروست کراوە

Supabase reads your tables and builds a REST API for them automatically, with a program called PostgREST: change the table and the API changes at once. Each table becomes a URL under https://<project-ref>.supabase.co/rest/v1/, and the HTTP method says what to do: POST inserts a row, GET reads rows (with filters such as ?device=eq.cage-01), PATCH updates and DELETE removes (REST). A successful insert answers 201 Created.

Supabase دەخوێنێتەوە و بە شێوەی خۆکار APIـیان بۆ دروست دەکات، بە بەرنامەیەک بە ناوی PostgREST: بگۆڕە و API یەکسەر دەگۆڕێت. هەر دەبێتە لە ژێر https://<project-ref>.supabase.co/rest/v1/ و دەڵێت چی بکرێت: POST ڕیزێک زیاد دەکات، GET ڕیز دەخوێنێتەوە (بە فلتەری وەک ?device=eq.cage-01)، PATCH دەگۆڕێت و DELETE دەسڕێتەوە (REST). زیادکردنێکی سەرکەوتوو بە 201 Created وەڵام دەداتەوە.

The base URL https://<project-ref>.supabase.co/rest/v1/readings and four rows: POST with the body {"device":"cage-01","temperature":24.5,"cover_open":true} adds a row, becomes INSERT and answers 201 Created; GET ?device=eq.cage-01&order=created_at.desc&limit=10 reads rows, becomes SELECT and answers 200 with a JSON array; PATCH ?id=eq.104 with {"cover_open":true} changes rows, becomes UPDATE, 204 No Content; DELETE ?created_at=lt.2026-01-01 removes rows, becomes DELETE, 204 No Content. Bottom: every request also carries the key in the apikey header; the rules decide what it may do.URLـی بنەڕەت https://<project-ref>.supabase.co/rest/v1/readings و چوار ڕیز: POST بە جەستەی {"device":"cage-01","temperature":24.5,"cover_open":true} ڕیزێک زیاد دەکات، دەبێتە INSERT و بە 201 Created وەڵام دەداتەوە؛ GET ?device=eq.cage-01&order=created_at.desc&limit=10 ڕیز دەخوێنێتەوە، دەبێتە SELECT و بە 200 و ڕیزەکێکی JSON وەڵام دەداتەوە؛ PATCH ?id=eq.104 بە {"cover_open":true} ڕیز دەگۆڕێت، دەبێتە UPDATE، 204 No Content؛ DELETE ?created_at=lt.2026-01-01 ڕیز دەسڕێتەوە، دەبێتە DELETE، 204 No Content. خوارەوە: هەموو داواکارییەک کلیلی APIـیەکەش لە سەردێڕی apikeyـدا هەڵدەگرێت؛ یاساکان دیاری دەکەن چی دەتوانێت بکات.
Methods map to SQL; filters go in the URL. دەبنە ؛ فلتەرەکان دەچنە ناو .CêIT
The request the board sends (placeholder key)ئەو داواکارییەی بۆردەکە دەینێرێت (کلیلی APIـیەکە جێگرەوەیە)HTTP
POST /rest/v1/readings HTTP/1.1
Host: your-project-ref.supabase.co
apikey: sb_publishable_REPLACE_WITH_YOUR_KEY
Content-Type: application/json
Prefer: return=minimal

{"device":"cage-01","temperature":24.5,"cover_open":true}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 3

The publishable key goes in the apikey header (new Supabase keys are not sent as Authorization: Bearer).

دەچێتە ناو سەردێڕی apikey ( نوێی Supabase وەک Authorization: Bearer نانێردرێن).

Lineدێڕی 5

return=minimal: answer 201 with no body, to save the board’s memory and data.

return=minimal: بە ⁦201⁩ بێ جەستە وەڵام بدەرەوە، بۆ پاشەکەوتی و بۆردەکە.

A REST API made for youREST APIـیەک کە بۆت دروست کراوە

Since October 2026: grant the table firstلە تشرینی یەکەمی ⁦2026⁩ـەوە: سەرەتا مۆڵەتی خشتەکە بدە

Supabase changed a default in 2026. New projects since 30 May 2026, and all existing projects since 30 October 2026, no longer open new tables to the API automatically. A table is reachable only after an explicit grant — an SQL permission that says which role may use it (GRANT and REVOKE). Without one, the API answers with error 42501, “permission denied for table readings” (HTTP 401 for the publishable key).

Supabase لە ⁦2026⁩ـدا ڕێکخستنێکی بنەڕەتیی گۆڕی. پرۆژە نوێکان لە ⁦30⁩ی ئایاری ⁦2026⁩ـەوە و هەموو پرۆژە کۆنەکان لە ⁦30⁩ی تشرینی یەکەمی ⁦2026⁩ـەوە ئیتر نوێیەکان بە شێوەی خۆکار بۆ API ناکەنەوە. تەنیا دوای مۆڵەتێکی ئاشکرا ⁦(grant)⁩ دەگاتێ — ڕێگەپێدانێکی کە دەڵێت کام ڕۆڵ دەتوانێت بەکاری بهێنێت (GRANT و REVOKE). بەبێ ئەو، API بە هەڵەی 42501 وەڵام دەداتەوە، «permission denied for table readings» (⁦HTTP 401⁩ بۆ ).

So grants and policies work as a pair: the grant opens the table to a role, and Row Level Security decides which rows that role may touch. Lines 14 and 21 of the SQL above are the grants.

کەواتە مۆڵەت و سیاسەت پێکەوە کار دەکەن: مۆڵەت بۆ ڕۆڵێک دەکاتەوە و دیاری دەکات ئەو ڕۆڵە دەتوانێت دەست لە کام ڕیزانە بدات. دێڕەکانی ⁦14⁩ و ⁦21⁩ی سەرەوە مۆڵەتەکانن.

A timeline of the 2026 Supabase change. 28 April 2026: a choice when you create a new project. 30 May 2026: the default for every new project. 30 October 2026: applied to all existing projects too. Below: without a grant, every request fails with error 42501 (HTTP 401 with the publishable key); the fix is the line grant insert on public.readings to anon; the grant opens the table to a role, and the RLS policy then checks each row.هێڵی کاتی گۆڕانکارییەکەی Supabase لە 2026دا. 28ی نیسانی 2026: هەڵبژاردنێک لە کاتی دروستکردنی پرۆژەیەکی نوێدا. 30ی ئایاری 2026: بنەڕەت بۆ هەموو پرۆژەیەکی نوێ. 30ی تشرینی یەکەمی 2026: بۆ هەموو پرۆژە کۆنەکانیش جێبەجێ کرا. لە خوارەوە: بەبێ مۆڵەت هەموو داواکارییەک بە هەڵەی 42501 سەرناکەوێت (HTTP 401 بە کلیلی ئاشکرا)؛ چارەسەرەکە دێڕی grant insert on public.readings to anon;ـە؛ مۆڵەت خشتەکە بۆ ڕۆڵێک دەکاتەوە و پاشان سیاسەتی ئاسایشی ئاستی ڕیز هەر ڕیزێک دەپشکنێت.
Since 30 October 2026 every Supabase project needs the grant.لە ⁦30⁩ی تشرینی یەکەمی ⁦2026⁩ـەوە هەموو پرۆژەیەکی Supabase مۆڵەتەکەی پێویستە.CêIT

Two keys: publishable and secretدوو کلیلی API: ئاشکرا و نهێنی

Every request carries an API key that tells Supabase which project and which role is asking. Supabase gives each project two kinds (as of November 2026):

هەموو هەڵدەگرێت کە بە Supabase دەڵێت کام پرۆژە و کام ڕۆڵ داوا دەکات. Supabase دوو جۆر دەداتە هەر پرۆژەیەک (تا تشرینی دووەمی ⁦2026⁩):

  • The publishable key (sb_publishable_…) is made to be public: it may sit in a board’s firmware, a phone app or a web page. It acts as the anon role (or authenticated once a user signs in), so it can do only what the grants and RLS policies allow.
  • The secret key (sb_secret_…) has full power: it acts as service_role, which bypasses Row Level Security. It belongs only on a server you control — never in firmware, an app, a browser or a public GitHub repository.
  • (sb_publishable_…) بۆ ئەوە دروست کراوە کە ئاشکرا بێت: دەتوانێت لە بۆردێک، ئەپێکی مۆبایل یان بێت. وەک ڕۆڵی anon کار دەکات (یان authenticated کاتێک بەکارهێنەرێک دەچێتە ژوورەوە)، بۆیە تەنیا ئەوە دەکات کە مۆڵەت و سیاسەتەکانی ڕێگەی دەدەن.
  • (sb_secret_…) دەسەڵاتی تەواوی هەیە: وەک service_role کار دەکات، کە تێدەپەڕێنێت. تەنیا لەسەر دەبێت کە خۆت کۆنترۆڵی دەکەیت — هەرگیز لە ، ئەپ، یان کۆگایەکی گشتیی GitHubـدا نا.
Two panels. Publishable key, sb_publishable_…: safe to put in a board or an app; anyone can find it, so it may do only what RLS allows; a board and a phone with a tick. Secret key, sb_secret_…: full power, it bypasses RLS; server only, never in a device, an app, a web page or GitHub; a server with a tick and a board crossed out. Bottom: the older anon and service_role keys (long JWTs) are being retired by the end of 2026, according to the Supabase docs checked in November 2026.دوو بەش. کلیلی ئاشکرا، sb_publishable_…: دەتوانرێت بخرێتە ناو بۆرد یان ئەپ؛ هەموو کەس دەتوانێت بیدۆزێتەوە، بۆیە تەنیا ئەوە دەکات کە ئاسایشی ئاستی ڕیز ڕێگەی دەدات؛ بۆردێک و مۆبایلێک بە نیشانەی ڕاست. کلیلی نهێنیی API، sb_secret_…: دەسەڵاتی تەواو، ئاسایشی ئاستی ڕیز تێدەپەڕێنێت؛ تەنیا لەسەر ڕاژەکار، هەرگیز لە ئامێر، ئەپ، لاپەڕەتۆڕ یان GitHub نا؛ ڕاژەکارێک بە نیشانەی ڕاست و بۆردێک بە خاچ. خوارەوە: کلیلەکانی APIـی کۆنی anon و service_role (JWTـی درێژ) تا کۆتایی 2026 لادەبرێن، بەپێی بەڵگەنامەکانی Supabase کە لە تشرینی دووەمی 2026 پشکنران.
The publishable key may travel; the secret key stays home. دەتوانێت بگەڕێت؛ لە ماڵەوە دەمێنێتەوە.CêIT

Two keys: publishable and secretدوو کلیلی API: ئاشکرا و نهێنی

Old keys and leaked keysکلیلەکانی APIـی کۆن و دزەکردوو

The older keys, anon and service_role (long JWTs starting with eyJ), work the same way but are being retired by the end of 2026; new projects should use the new pair (API keys).

کۆن، anon و service_role (JWTـی درێژ کە بە eyJ دەست پێ دەکەن)، بە هەمان شێوە کار دەکەن، بەڵام تا کۆتایی ⁦2026⁩ لادەبرێن؛ پرۆژە نوێکان دەبێت جووتە نوێیەکە بەکار بهێنن (کلیلەکانی API).

Row Level Security: the gate at every rowئاسایشی ئاستی ڕیز: دەرگا لە هەر ڕیزێکدا

Definitionپێناسە

rules that decide, row by row, who may read or change each of a . In Supabase they make it safe to use a in a device.

یاساکانی کە ڕیز بە ڕیز بڕیار دەدەن کێ دەتوانێت هەر بخوێنێتەوە یان بیگۆڕێت. لە Supabaseـدا وا دەکەن بەکارهێنانی لەناو ئامێرێکدا سەلامەت بێت.

With RLS switched on and no policies, the publishable key can reach no data at all. Each policy then opens one narrow door: for insert … with check (…) says which new rows a role may add; for select … using (…) says which rows it may read. In the readings table the board (role anon) may only insert rows for cage-01, and signed-in app users (role authenticated) may only read. Nobody may update or delete through the API. This is the same idea as Firebase Security Rules (security rules).

کاتێک هەڵکراوە و هیچ سیاسەتێک نییە، ناگاتە هیچ . پاشان هەر سیاسەتێک دەرگایەکی تەسک دەکاتەوە: for insert … with check (…) دەڵێت ڕۆڵێک کام ڕیزی نوێ دەتوانێت زیاد بکات؛ for select … using (…) دەڵێت کام ڕیزانە دەتوانێت بخوێنێتەوە. لە خوێندنەوەکاندا بۆردەکە (ڕۆڵی anon) تەنیا دەتوانێت ڕیز بۆ cage-01 زیاد بکات و بەکارهێنەرانی چووەژوورەوەی ئەپ (ڕۆڵی authenticated) تەنیا دەتوانن بخوێننەوە. هیچ کەس لە ڕێگەی APIـیەوە ناتوانێت بیگۆڕێت یان بیسڕێتەوە. ئەمە هەمان بیرۆکەی Firebase Security Rulesـە (یاساکانی ئاسایش).

Three requests with the publishable key pass two gates on the way to the readings table. Gate 1, grant: may this role use the table at all? Gate 2, RLS policy: is this row allowed? POST temperature 24.5 passes both gates: row added (201). POST device "my-laptop" passes the grant but the policy refuses it (401). GET all readings stops at gate 1: refused, no grant (401). Bottom: grants open the door to a table; RLS policies decide row by row; the secret key skips both.سێ داواکاری بە کلیلی ئاشکرا لە ڕێگەی خشتەی readingsـدا بە دوو دەرگادا تێدەپەڕن. دەرگای 1، مۆڵەت: ئەم ڕۆڵە دەتوانێت خشتەکە بەکار بهێنێت؟ دەرگای 2، سیاسەتی ئاسایشی ئاستی ڕیز: ئەم ڕیزە ڕێگەپێدراوە؟ POSTـی پلەی گەرمیی 24.5 بە هەردوو دەرگادا تێدەپەڕێت: ڕیز زیاد کرا (201). POSTـی ئامێری "my-laptop" بە مۆڵەتدا تێدەپەڕێت، بەڵام سیاسەتەکە ڕەتی دەکاتەوە (401). GETـی هەموو خوێندنەوەکان لە دەرگای 1 دەوەستێت: ڕەت کرایەوە، مۆڵەت نییە (401). خوارەوە: مۆڵەتەکان دەرگای خشتەیەک دەکەنەوە؛ سیاسەتەکانی ئاسایشی ئاستی ڕیز ڕیز بە ڕیز بڕیار دەدەن؛ کلیلی نهێنیی API هەردووکیان تێدەپەڕێنێت.
A grant opens the table; a policy checks each row.مۆڵەت دەکاتەوە؛ سیاسەت هەر ڕیزێک دەپشکنێت.CêIT

Sending a reading from the boardناردنی خوێندنەوەیەک لە بۆردەکەوە

The device is a Nano ESP32, a Wi-Fi board (boards for IoT), with a DHT11 on pin 2 and the cover’s limit switch on pin 3 (limit switch). Every minute the sketch reads both, builds one JSON row and POSTs it over HTTPS.

ئامێرەکە ⁦Nano ESP32⁩ـە، بۆردێکی (بۆردەکان بۆ IoT)، لەگەڵ ⁦DHT11⁩ لەسەر پینی 2 و بەرگەکە لەسەر پینی 3 (سویچی سنوور). هەموو خولەکێک هەردووکیان دەخوێنێتەوە، ڕیزێکی دروست دەکات و بە POSTی دەکات.

Wiring: a DHT11 connects to a Nano ESP32 (3.3 V) with 3.3 V, DATA to D2 and GND; a limit switch connects between D3 and GND. Notes: pin 2 is the DHT11 data; pin 3 uses INPUT_PULLUP, so pressed reads LOW, and pressed means the cover is closed. The board sends over Wi-Fi. Warning: low-voltage parts only; the board never touches mains electricity.بەستنەوە: DHT11 بە 3.3 V، DATA بۆ D2 و GND بە Nano ESP32 (3.3 V)ـەوە دەبەسترێت؛ سویچێکی سنوور لە نێوان D3 و GNDـدایە. تێبینی: پینی 2 دراوەی DHT11ـە؛ پینی 3 INPUT_PULLUP بەکار دەهێنێت، بۆیە پەستێنراو LOW دەخوێنێتەوە و پەستێنراو واتە بەرگەکە داخراوە. بۆردەکە بە وای‌فای دەنێرێت. ئاگاداری: تەنیا پارچەی ڤۆڵتی نزم؛ بۆردەکە هەرگیز دەست لە کارەبای ماڵ نادات.
Two inputs, one Wi-Fi board.دوو ، یەک بۆردی .CêIT
Secrets in their own file (placeholders)نهێنییەکان لە فایلێکی جیادا (جێگرەوە)arduino_secrets.hARDUINORuns on a phone (or an emulator)لەسەر مۆبایل کار دەکات
// Never share this file or upload it to GitHub.
#define SECRET_SSID    "your-wifi-name"
#define SECRET_PASS    "your-wifi-password"
#define SUPABASE_URL   "https://your-project-ref.supabase.co"
#define SUPABASE_KEY   "sb_publishable_REPLACE_WITH_YOUR_KEY"   // publishable only, never the secret key
#define SECRET_ROOT_CA "-----BEGIN CERTIFICATE-----\n...the server's root certificate...\n-----END CERTIFICATE-----\n"
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 5

Only the publishable key ever goes here.

تەنیا دەچێتە ئێرە.

Add one row every minuteزیادکردنی ڕیزێک هەموو خولەکێکsupabase_post.inoARDUINORuns on a phone (or an emulator)لەسەر مۆبایل کار دەکات
// Add one reading to the Supabase table "readings" every minute (Nano ESP32)
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <DHT.h>
#include "arduino_secrets.h"   // Wi-Fi, project URL, publishable key, root certificate

DHT dht(2, DHT11);             // DHT11 data pin on pin 2
const int closedSwitch = 3;    // limit switch: pressed (LOW) = cover closed
WiFiClientSecure tls;

void setup() {
  Serial.begin(115200);
  dht.begin();
  pinMode(closedSwitch, INPUT_PULLUP);
  WiFi.begin(SECRET_SSID, SECRET_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
  Serial.println("Wi-Fi connected");
  tls.setCACert(SECRET_ROOT_CA);            // HTTPS: check the server's certificate
}

void loop() {
  float t = dht.readTemperature();
  bool coverOpen = digitalRead(closedSwitch) == HIGH;
  if (isnan(t)) {
    Serial.println("DHT11 read failed: nothing sent");
  } else {
    String body = "{\"device\":\"cage-01\",\"temperature\":" + String(t, 1) +
                  ",\"cover_open\":" + (coverOpen ? "true" : "false") + "}";
    HTTPClient http;
    http.begin(tls, String(SUPABASE_URL) + "/rest/v1/readings");
    http.addHeader("apikey", SUPABASE_KEY);
    http.addHeader("Content-Type", "application/json");
    http.addHeader("Prefer", "return=minimal");
    int code = http.POST(body);             // 201 = the row was added
    http.end();
    Serial.println(body + " -> HTTP " + String(code));
  }
  delay(60000);                              // the next reading in a minute
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 19

HTTPS: the board checks the server’s certificate before sending anything.

: بۆردەکە پێش ناردنی هەر شتێک دەپشکنێت.

Lineدێڕی 24

Pressed switch (LOW) = cover closed, so HIGH means not closed.

پەستێنراو ⁦(LOW)⁩ = بەرگی داخراو، بۆیە HIGH واتە دانەخراو.

Lineدێڕی 25-26

A failed DHT11 read sends nothing (NaN is not valid JSON).

خوێندنەوەیەکی تێکچووی ⁦DHT11⁩ هیچ نانێرێت (NaN دروست نییە).

Lineدێڕی 28-29

Only the three columns the board knows; id and created_at come from the database.

تەنیا ئەو سێ بۆردەکە دەیانزانێت؛ id و ⁦created_at⁩ لە دێن.

Lineدێڕی 32-34

The three headers: the key, the format, and “no body back, please”.

سێ سەردێڕەکە: ، شێوازەکە و «تکایە جەستە مەگەڕێنەرەوە».

Lineدێڕی 35

POST() returns the HTTP status code, or a negative number if there was no connection.

POST() دەگەڕێنێتەوە، یان ژمارەیەکی نەرێنی ئەگەر پەیوەندی نەبوو.

Sending a reading from the boardناردنی خوێندنەوەیەک لە بۆردەکەوە

What the reply tells the boardوەڵامەکە چی بە بۆردەکە دەڵێت

A device far from anyone must decide by itself what to do when sending fails, so the sketch should look at the code that POST() returns. With the publishable key, PostgREST answers 401 both for a wrong key and for a missing grant or a refused policy (the body then contains error 42501); a wrong column or a broken check gives 400. A negative number means the request never reached the server.

ئامێرێک کە لە هەموو کەس دوورە دەبێت خۆی بڕیار بدات چی بکات کاتێک ناردن سەرناکەوێت، بۆیە دەبێت سەیری ئەو کۆدە بکات کە POST() دەیگەڕێنێتەوە. بە ، PostgREST هەم بۆ هەڵە و هەم بۆ نەبوونی مۆڵەت یان ڕەتکردنەوەی سیاسەت ⁦401⁩ دەداتەوە (لەو کاتەدا جەستەکە هەڵەی 42501ـی تێدایە)؛ هەڵە یان checkـێکی شکاو ⁦400⁩ دەدات. ژمارەیەکی نەرێنی واتە هەرگیز نەگەیشتووەتە .

Four rows. 201: the row was added; carry on. 400: bad JSON, a wrong column or a broken rule; fix the sketch. 401: wrong key, or no grant or policy (code 42501); check the key and the rules. A negative number such as −1: no connection, Wi-Fi, DNS or TLS; keep the reading and retry later. Bottom: with the publishable key, PostgREST answers 401 both for a wrong key and for a missing grant or policy.چوار ڕیز. 201: ڕیزەکە زیاد کرا؛ بەردەوام بە. 400: JSONـی هەڵە، ستوونی هەڵە یان یاسایەکی شکاو؛ سکێچەکە چاک بکە. 401: کلیلی APIـی هەڵە، یان مۆڵەت یان سیاسەت نییە (کۆدی 42501)؛ کلیلی API و یاساکان بپشکنە. ژمارەیەکی نەرێنی وەک −1: پەیوەندی نییە، وای‌فای، DNS یان TLS؛ خوێندنەوەکە ڕابگرە و دواتر هەوڵ بدەرەوە. خوارەوە: بە کلیلی ئاشکرا، PostgREST بۆ کلیلی APIـی هەڵە و بۆ نەبوونی مۆڵەت یان سیاسەت هەر 401 دەداتەوە.
Read the code, then act: retry, fix the sketch, or fix the rules.کۆدەکە بخوێنەرەوە، پاشان کار بکە: دووپاتە هەوڵ بدە، چاک بکە یان یاساکان چاک بکە.CêIT

Dashboards: seeing the dataداشبۆردەکان: بینینی دراوە

Definitionپێناسە

A screen that shows the most important live of a system at a glance, with numbers, charts and alerts, such as today's temperatures from all sensors.

شاشەیەکە کە گرنگترین ڕاستەوخۆی سیستەمێک بە یەک سەیرکردن پیشان دەدات، بە ژمارە، و ئاگادارکردنەوە، وەک پلەی گەرمیی ئەمڕۆ لە هەموو .

Rows are hard to read; a chart is not. A dashboard for the cage could show the temperature line for the last day against the 20–25 °C target, and when the cover was open. Supabase’s own Table Editor shows the rows, and dashboard tools such as Grafana can connect straight to a Postgres database. Behind each chart is a query; this one, run in the SQL Editor, gives one average per hour:

خوێندنەوەی ڕیزەکان قورسە؛ نا. بۆ قەفەزەکە دەتوانێت هێڵی پلەی گەرمیی دوایین ڕۆژ بەرامبەر ئامانجی ⁦20–25 °C⁩ پیشان بدات، لەگەڵ ئەوەی بەرگەکە کەی کراوە بوو. Table Editorـی خودی Supabase ڕیزەکان پیشان دەدات و ئامرازەکانی وەک Grafana دەتوانن ڕاستەوخۆ بە Postgresـەوە ببەسترێن. لە پشت هەر هەیە؛ ئەمەیان، کە لە SQL Editorـدا کار دەکات، بۆ هەر کاتژمێرێک تێکڕایەک دەدات:

One average per hour for the last dayتێکڕایەک بۆ هەر کاتژمێرێک لە دوایین ڕۆژداSQLRuns in the databaseلە ناو بنکەدراوە کار دەکات
select date_trunc('hour', created_at) as hour,
       round(avg(temperature)::numeric, 1) as avg_temp
from public.readings
where device = 'cage-01'
  and created_at > now() - interval '1 day'
group by hour
order by hour;
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 1

date_trunc cuts each time down to its hour, so readings fall into hourly groups.

date_trunc هەر کاتێک دەبڕێتەوە بۆ کاتژمێرەکەی، بۆیە خوێندنەوەکان دەکەونە گرووپی کاتژمێری.

Lineدێڕی 2

::numeric is needed because Postgres rounds to one decimal only on numeric values.

::numeric پێویستە چونکە Postgres تەنیا لەسەر نرخی numeric بۆ یەک ژمارەی دوای فاریزە دەیخڕێنێت.

Line chart of the cage temperature on 5 November 2026, example data, one point per hour from 00:00 to 24:00, with a shaded target band from 20 to 25 °C. The line falls from 22.1 °C at midnight to a low of 20.4 °C at 05:00, rises to a high of 24.8 °C at 15:00 and ends at 22.1 °C. A strip below shows the cover closed until 06:00, open from 06:00 to 19:00 and closed again after 19:00. Note: one point per hour is shown; the table holds one reading per minute.هێڵکاریی هێڵی پلەی گەرمیی قەفەزەکە لە 5ی تشرینی دووەمی 2026، دراوەی نموونە، خاڵێک بۆ هەر کاتژمێرێک لە 00:00 تا 24:00، لەگەڵ شریتێکی ئامانج لە 20 تا 25 °C. هێڵەکە لە 22.1 °C لە نیوەشەودا دادەبەزێت بۆ نزمترین 20.4 °C لە 05:00، بەرز دەبێتەوە بۆ بەرزترین 24.8 °C لە 15:00 و بە 22.1 °C کۆتایی دێت. شریتێک لە خوارەوە پیشان دەدات بەرگەکە تا 06:00 داخراوە، لە 06:00 تا 19:00 کراوەیە و دوای 19:00 دیسان داخراوە. تێبینی: بۆ هەر کاتژمێرێک خاڵێک پیشان دراوە؛ خشتەکە هەر خولەکێک خوێندنەوەیەک هەڵدەگرێت.
A day in one picture: the temperature stayed inside the target.ڕۆژێک لە یەک وێنەدا: پلەی گەرمی لە ناو ئامانجدا مایەوە.CêIT

Dashboards: seeing the dataداشبۆردەکان: بینینی دراوە

A new row every minuteهەر خولەکێک ڕیزێکی نوێ

Watch the table and the chart grow. Each minute the board POSTs, the API answers 201 and one more row appears. With Supabase Realtime, a dashboard or app can subscribe to the table and receive each new row as soon as it is inserted, instead of asking again and again — the same push idea as MQTT (publish and subscribe).

سەیری گەشەکردنی و بکە. هەموو خولەکێک بۆردەکە POST دەکات، API بە ⁦201⁩ وەڵام دەداتەوە و ڕیزێکی تر دەردەکەوێت. بە Realtimeـی Supabase، یان ئەپێک دەتوانێت بەشداری بێت و هەر ڕیزێکی نوێ هەر کە زیاد کرا وەربگرێت، لە جیاتی ئەوەی هەر بپرسێت — هەمان بیرۆکەی ناردنی ڕاستەوخۆی (بڵاوکردنەوە و بەشداربوون).

Animation in four steps. A board labelled cage-01 POSTs and gets 201; each minute one more row appears in the readings table, from 10:01 to 10:04, and the newest row is highlighted. A small live chart below adds one point each minute: 24.5, 24.5, 24.3, 24.1 and 24.1 °C.
Animation in four steps. A board labelled cage-01 POSTs and gets 201; each minute one more row appears in the readings table, from 10:01 to 10:04, and the newest row is highlighted. A small live chart below adds one point each minute: 24.5, 24.5, 24.3, 24.1 and 24.1 °C.
Every minute, one POST, one 201, one new row.هەموو خولەکێک، یەک POST، یەک ⁦201⁩، یەک ڕیزی نوێ.CêIT

The phone appئەپی مۆبایل

The owner wants to see the cage from anywhere. The phone app holds only the publishable key, lets the user sign in (role authenticated), and then reads the newest rows with a GET request — exactly the HTTP and JSON skills of the Flutter track (HTTP and JSON in Flutter) — or receives new rows through Realtime. Supabase also has an official Flutter package that wraps these calls. The app, like the board, never holds the secret key.

خاوەنەکە دەیەوێت لە هەر شوێنێکەوە قەفەزەکە ببینێت. ئەپی مۆبایل تەنیا هەڵدەگرێت، ڕێگە بە بەکارهێنەر دەدات بچێتە ژوورەوە (ڕۆڵی authenticated) و پاشان نوێترین ڕیزەکان بە GET دەخوێنێتەوە — ڕێک تواناکانی و بەشی Flutter (HTTP و JSON لە Flutterـدا) — یان ڕیزە نوێیەکان لە ڕێگەی Realtimeـەوە وەردەگرێت. Supabase هەروەها پاکێجێکی فەرمیی Flutterـی هەیە کە ئەم بانگکردنانە ئاسان دەکات. ئەپەکە، وەک بۆردەکە، هەرگیز هەڵناگرێت.

A phone screen titled Bird cage shows 24.1 °C, inside the target 20–25 °C, a badge saying cover: closed, a small line of the last 8 hours and updated 10:03. Notes beside it: signs in, role authenticated; holds only the publishable key; reads rows with GET; or gets each new row with Realtime. A box: built in the Mobile App Development course, HTTP and JSON in Flutter and a back end as a service.شاشەی مۆبایلێک بە ناونیشانی قەفەزی باڵندە 24.1 °C پیشان دەدات، لە ناو ئامانجی 20–25 °C، نیشانەیەک کە دەڵێت بەرگ: داخراو، هێڵێکی بچووکی دوایین 8 کاتژمێر و نوێکراوە 10:03. تێبینی لە تەنیشتیەوە: دەچێتە ژوورەوە، ڕۆڵی authenticated؛ تەنیا کلیلی ئاشکرا هەڵدەگرێت؛ ڕیزەکان بە GET دەخوێنێتەوە؛ یان هەر ڕیزێکی نوێ بە Realtime وەردەگرێت. چوارگۆشەیەک: لە خولی پەرەپێدانی ئەپی مۆبایلدا دروست دەکرێت، HTTP و JSON لە Flutterـدا و BaaS.
The app reads; the board writes; the rules keep them apart.ئەپەکە دەخوێنێتەوە؛ بۆردەکە دەنووسێت؛ یاساکان لێکیان جیا دەکەنەوە.CêIT

Firebase comparedبەراوردکردن لەگەڵ Firebase

Firebase, Google’s BaaS, can store the same readings in Cloud Firestore, a NoSQL database: instead of rows in a table, each reading is a document of fields in a collection called readings, and documents may have different fields (Firestore’s data model). Firebase Security Rules play the part of RLS. Supabase was described in this course’s project as “similar to Google Firebase”; the real difference is the database underneath.

Firebase، Google، دەتوانێت هەمان خوێندنەوەکان لە Cloud Firestoreـدا هەڵبگرێت، کە : لە جیاتی ڕیز لە ، هەر خوێندنەوەیەک بەڵگەنامەیەکە لە لە ناو کۆمەڵەیەکدا بە ناوی readings و بەڵگەنامەکان دەتوانن جیاوازیان هەبێت (مۆدێلی دراوەی Firestore). Firebase Security Rules ڕۆڵی دەگێڕن. لە پرۆژەی ئەم خولەدا Supabase وەک «هاوشێوەی Firebaseـی Google» باس کراوە؛ جیاوازیی ڕاستەقینە ئەو لە ژێرەوەیە.

Two BaaS choices for IoT readings.دوو هەڵبژاردەی بۆ خوێندنەوەکانی IoT.
FeatureتایبەتمەندیSupabaseFirebase (Firestore)
DatabasePostgres: relational tablesPostgres: پەیوەندیدارFirestore: NoSQL documentsFirestore: بەڵگەنامەی
Shape of dataشێوەی fixed, typed columns جێگیر و جۆرداکراوflexible fields per document نەرم بۆ هەر بەڵگەنامەیەک
Queriesfull SQL: filters, joins, averages تەواو: فلتەر، بەستنەوە، تێکڕاsimpler queries: count, sum and average, but no GROUP BY or joins سادەتر: ژماردن، کۆ و تێکڕا، بەڵام بێ GROUP BY و بەستنەوە
Protectionپاراستنgrants + RLS policiesمۆڵەت + سیاسەتی Firebase Security Rules
Reach from a boardگەیشتن لە بۆردەوەREST API over HTTPS API بە REST API or an SDK API یان
The same reading in two kinds of database. Left, Supabase, a Postgres table with the columns created_at, device, temperature and cover_open and two rows; bullet points: fixed, typed columns; SQL queries, joins, sums; rules: grants and RLS policies. Right, Firebase, a Firestore document readings/3fT9kq2 with device "cage-01", temperature 24.1, cover_open false and created_at timestamp; bullet points: collections of documents (NoSQL); documents may differ; rules: Firebase Security Rules. Bottom: both are back ends as a service; in both, the rules, not a secret app key, protect the data.هەمان خوێندنەوە لە دوو جۆر بنکەدراوەدا. چەپ، Supabase، خشتەیەکی Postgres بە ستوونەکانی created_at، device، temperature و cover_open و دوو ڕیز؛ خاڵەکان: ستوونی جێگیر و جۆرداکراو؛ پرسی SQL، بەستنەوە، کۆکردنەوە؛ یاسا: مۆڵەت و سیاسەتی ئاسایشی ئاستی ڕیز. ڕاست، Firebase، بەڵگەنامەیەکی Firestore بە ناوی readings/3fT9kq2 بە device "cage-01"، temperature 24.1، cover_open false و created_at timestamp؛ خاڵەکان: کۆمەڵەی بەڵگەنامە (NoSQL)؛ بەڵگەنامەکان دەتوانن جیاواز بن؛ یاسا: Firebase Security Rules. خوارەوە: هەردووکیان BaaSـن؛ لە هەردووکیاندا یاساکان، نەک کلیلێکی نهێنیی APIـی ئەپ، دراوەکە دەپارێزن.
Rows in a table, or documents in a collection.ڕیز لە ، یان بەڵگەنامە لە کۆمەڵەیەکدا.CêIT

Common mistakesهەڵە باوەکان

Exercisesڕاهێنانەکان

ExerciseڕاهێنانA greenhouse tableخشتەیەکی گوڵخانە

Write the SQL for a table greenhouse that stores, per reading, the device name, the air temperature (decimal), the soil moisture in % (a whole number from 0 to 100) and whether the pump is on. Let the database number the rows and add the time.

بە ناوی greenhouse بنووسە کە بۆ هەر خوێندنەوەیەک ناوی ئامێرەکە، پلەی گەرمیی هەوا (کەرتی)، شێی خاک بە % ( لە 0 تا ⁦100⁩) و ئایا پەمپەکە هەڵکراوە هەڵدەگرێت. با ژمارە بداتە ڕیزەکان و کاتەکە زیاد بکات.

Show answerوەڵامەکە پیشان بدە
One possible answerوەڵامێکی گونجاوSQLRuns in the databaseلە ناو بنکەدراوە کار دەکات
create table public.greenhouse (
  id            bigint generated always as identity primary key,
  created_at    timestamptz not null default now(),
  device        text not null,
  temperature   double precision not null,
  soil_moisture integer not null check (soil_moisture between 0 and 100),
  pump_on       boolean not null
);
alter table public.greenhouse enable row level security;
ExerciseڕاهێنانThe board’s JSONJSONـی بۆردەکە

For that table, write the JSON body a board sends for: device gh-01, 29.4 °C, soil 37 %, pump off. Which headers does the request need?

بۆ ئەو ، ئەو جەستە بنووسە کە بۆردێک دەینێرێت بۆ: ئامێری ⁦gh-01⁩، ⁦29.4 °C⁩، خاک ⁦37 %⁩، پەمپ کوژاوە. کام سەردێڕانەی پێویستە؟

Show answerوەڵامەکە پیشان بدە

{"device": "gh-01", "temperature": 29.4, "soil_moisture": 37, "pump_on": false} — POST to /rest/v1/greenhouse with apikey: <publishable key>, Content-Type: application/json and, optionally, Prefer: return=minimal. No id and no created_at: the database adds them.

{"device": "gh-01", "temperature": 29.4, "soil_moisture": 37, "pump_on": false} — POST بۆ /rest/v1/greenhouse بە apikey: <publishable key>، Content-Type: application/json و بە ئارەزووی خۆت Prefer: return=minimal. نە id و نە ⁦created_at⁩: زیادیان دەکات.

ExerciseڕاهێنانWrite the policiesسیاسەتەکان بنووسە

For greenhouse: boards using the publishable key may only insert rows whose device starts with gh-; signed-in users may read all rows. Write the grants and the policies.

بۆ greenhouse: ئەو بۆردانەی بەکار دەهێنن تەنیا دەتوانن ئەو ڕیزانە زیاد بکەن کە ناوی ئامێرەکەیان بە gh- دەست پێ دەکات؛ بەکارهێنەرانی چووەژوورەوە دەتوانن هەموو ڕیزەکان بخوێننەوە. مۆڵەت و سیاسەتەکان بنووسە.

Show answerوەڵامەکە پیشان بدە
One possible answerوەڵامێکی گونجاوSQLRuns in the databaseلە ناو بنکەدراوە کار دەکات
grant insert on public.greenhouse to anon;
create policy "boards add greenhouse rows"
  on public.greenhouse for insert
  to anon
  with check (device like 'gh-%');

grant select on public.greenhouse to authenticated;
create policy "users read greenhouse rows"
  on public.greenhouse for select
  to authenticated
  using (true);
ExerciseڕاهێنانWhich key, where?کام کلیلی API، لە کوێ؟

Say which key (publishable, secret or none) belongs in each place: (a) the bird-cage sketch; (b) the Flutter app; (c) a nightly server script that deletes readings older than a year; (d) a public GitHub repository of the project.

بڵێ کام (ئاشکرا، نهێنی یان هیچ) لە هەر شوێنێکدا دەبێت: ⁦(a)⁩ قەفەزی باڵندە؛ ⁦(b)⁩ ئەپی Flutter؛ ⁦(c)⁩ بەرنامەیەکی شەوانەی کە خوێندنەوەی کۆنتر لە ساڵێک دەسڕێتەوە؛ ⁦(d)⁩ کۆگایەکی گشتیی GitHubـی پرۆژەکە.

Show answerوەڵامەکە پیشان بدە

(a) publishable; (b) publishable, with the user signing in; (c) secret, because it runs on your own server and must delete past RLS; (d) none — only placeholders, with real keys kept in an ignored file such as arduino_secrets.h.

⁦(a)⁩ ئاشکرا؛ ⁦(b)⁩ ئاشکرا، لەگەڵ چوونەژوورەوەی بەکارهێنەر؛ ⁦(c)⁩ نهێنی، چونکە لەسەر خۆت کار دەکات و دەبێت بۆ سڕینەوە تێبپەڕێنێت؛ ⁦(d)⁩ هیچ — تەنیا جێگرەوە؛ ڕاستەقینە لە فایلێکی پشتگوێخراودا دەمێننەوە، وەک arduino_secrets.h.

ExerciseڕاهێنانRead the replyوەڵامەکە بخوێنەرەوە

What should the board do after each reply? (a) 201; (b) 401 with 42501 in the body; (c) −1; (d) 400 after a firmware update.

بۆردەکە دوای هەر وەڵامێک چی بکات؟ ⁦(a) 201⁩؛ ⁦(b) 401⁩ لەگەڵ 42501 لە جەستەکەدا؛ ⁦(c) −1⁩؛ ⁦(d) 400⁩ دوای نوێکردنەوەی .

Show answerوەڵامەکە پیشان بدە

(a) Nothing special: the row is stored. (b) Stop retrying and report it: a grant or a policy is missing, and resending will not help. (c) Keep the reading and retry later: the network or the server could not be reached. (d) The new firmware sends JSON that does not match the table: fix the sketch or the columns.

⁦(a)⁩ هیچی تایبەت: ڕیزەکە هەڵگیرا. ⁦(b)⁩ دووپاتە هەوڵدان ڕابگرە و ڕاپۆرتی بکە: مۆڵەتێک یان سیاسەتێک کەمە و دووپاتە ناردن سوودی نییە. ⁦(c)⁩ خوێندنەوەکە ڕابگرە و دواتر هەوڵ بدەرەوە: نەگەیشتە یان . ⁦(d)⁩ نوێیەکە دەنێرێت کە لەگەڵ یەک ناگرێتەوە: یان چاک بکە.

Summaryپوختە

  • A cloud back end stores, searches and shows readings; a BaaS such as Supabase gives a Postgres database, an API and sign-in ready-made.
  • One reading = one row of a typed table: id, created_at (set by the database), device, temperature (double), cover_open (Boolean).
  • PostgREST makes /rest/v1/<table>: POST inserts (201), GET reads with filters, PATCH updates, DELETE removes.
  • Since October 2026 a table needs explicit grants; RLS policies then decide row by row.
  • The publishable key may live in boards and apps; the secret key bypasses RLS and stays on a server. The old anon/service_role keys are retired by the end of 2026.
  • Dashboards and the phone app read the table (GET or Realtime); Firebase Firestore is the NoSQL alternative with Security Rules.
  • هەوری خوێندنەوەکان هەڵدەگرێت، دەگەڕێت و پیشانیان دەدات؛ وەک Supabase Postgres، API و چوونەژوورەوە بە ئامادەیی دەدات.
  • یەک خوێندنەوە = یەک ڕیز لە جۆرداکراو: id، ⁦created_at⁩ ( دایدەنێت)، device، ⁦temperature (double)⁩، ⁦cover_open⁩ ().
  • PostgREST /rest/v1/<table> دروست دەکات: POST زیاد دەکات ⁦(201)⁩، GET بە فلتەر دەخوێنێتەوە، PATCH دەگۆڕێت، DELETE دەسڕێتەوە.
  • لە تشرینی یەکەمی ⁦2026⁩ـەوە مۆڵەتی ئاشکرای دەوێت؛ پاشان سیاسەتەکانی ڕیز بە ڕیز بڕیار دەدەن.
  • دەتوانێت لە بۆرد و ئەپدا بێت؛ تێدەپەڕێنێت و لەسەر دەمێنێتەوە. کۆنی ⁦anon/service_role⁩ تا کۆتایی ⁦2026⁩ لادەبرێن.
  • و ئەپی مۆبایل دەخوێننەوە (GET یان Realtime)؛ Firebase Firestore جێگرەوەی بە Security Rules.

Next: Keeping IoT devices safe and private, then the course project, a smart bird-cage cover, which puts the sensors, the motor and this cloud table together.

داهاتوو: پاراستنی ئامێرەکانی IoT و تایبەتمەندییان، پاشان پرۆژەی خولەکە، بەرگی هۆشمەندی قەفەزی باڵندە، کە ، بزوێنەرەکە و ئەم هەوریە پێکەوە دەبەستێتەوە.

Lesson complete!وانەکە تەواو بوو!

Well done. Review the key terms, then go on to the next lesson.دەستخۆش. سەیرێکی زاراوە سەرەکییەکان بکەرەوە، پاشان بڕۆ بۆ وانەی داهاتوو.

Key termsزاراوە سەرەکییەکان

Next lessonوانەی داهاتوو

Keeping IoT Devices Safe and Privateئامێرەکانی IoT: ئاسایش و تایبەتێتی

References and further readingسەرچاوەکان و خوێندنەوەی زیاتر

This lecture is a first edition. The Kurdish text and terminology are waiting for review by Kurdish IT teachers.ئەم وانەیە چاپی یەکەمە. دەقە کوردییەکە و زاراوەکانی چاوەڕێی پێداچوونەوەی مامۆستایانی کوردی بواری IT ن.

Appearanceڕووکار

Modeدۆخ
Styleشێواز
Coloursڕەنگەکان

Saved on this device only.تەنیا لەسەر ئەم ئامێرە پاشەکەوت دەکرێت.