{"id":144933,"date":"2024-01-18T14:46:37","date_gmt":"2024-01-18T14:46:37","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=144933"},"modified":"2025-01-15T10:42:30","modified_gmt":"2025-01-15T10:42:30","slug":"esp32-datalogging-google-sheets","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-datalogging-google-sheets\/","title":{"rendered":"ESP32 Datalogging to Google Sheets (using Google Service Account)"},"content":{"rendered":"\n<p>In this project, you&#8217;ll learn how to log data to Google Sheets with the ESP32 securely and reliably using a Google Service Account and Google Sheets API. We&#8217;ll use the Arduino Google Sheets Client Library. After explaining the most important basic concepts, we&#8217;ll build a Datalogger that saves temperature, humidity, pressure, and corresponding timestamp on a Google spreadsheet.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-Publish-Google-sheets.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Datalogging to Google Sheets using Google Service Account\" class=\"wp-image-144999\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-Publish-Google-sheets.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-Publish-Google-sheets.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-Publish-Google-sheets.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-Publish-Google-sheets.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>To successfully follow this tutorial, make sure you follow all the next steps in the following order:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"#prerequisites\" title=\"\">Prerequisites<\/a><\/li>\n\n\n\n<li><a href=\"#google-service-account\" title=\"\">Google Service Account<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"#create-service-account\" title=\"\">Create a Service Account<\/a><\/li>\n\n\n\n<li><a href=\"#create-key\" title=\"\">Creating a New Key<\/a><\/li>\n\n\n\n<li><a href=\"#enable-google-sheet-api\" title=\"\">Enable Google Sheet API<\/a><\/li>\n\n\n\n<li><a href=\"#enable-google-drive-api\" title=\"\">Enable Google Drive API<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"#install-gsheets-library-arduino\" title=\"\">Installing the Arduino Google Sheet Client Library<\/a><\/li>\n\n\n\n<li><a href=\"#create-google-spreadsheet\" title=\"\">Creating a Google Spreadsheet<\/a><\/li>\n\n\n\n<li><a href=\"#share-spreadsheet\" title=\"\">Sharing the Spreadsheet with the Service Account<\/a><\/li>\n\n\n\n<li><a href=\"#esp32-bme280\" title=\"\">ESP32 with BME280 Circuit<\/a><\/li>\n\n\n\n<li><a href=\"#esp32-gsheet-datalogger-arduino-code\" title=\"\">ESP32 Datalogging to Google Sheets &#8211; Arduino Sketch<\/a><\/li>\n<\/ol>\n\n\n\n<p class=\"rntbox rntclgray\"><strong>Note<\/strong>: we have another tutorial showing how to send data to Google Sheets, but using IFTTT: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-publish-sensor-readings-to-google-sheets\/#more-56442\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP32 Publish Sensor Readings to Google Sheets (ESP8266 Compatible)<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"prerequisites\">1. Prerequisites<\/h2>\n\n\n\n<p>Before following this tutorial, make sure you check the following prerequisites:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Google Account<\/h3>\n\n\n\n<p>You need a Google Account to follow this project. If you don&#8217;t have a Google account, you can <a href=\"https:\/\/accounts.google.com\/\" target=\"_blank\" rel=\"noopener\" title=\"\">create one <\/a>here.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">ESP32 with Arduino IDE<\/h3>\n\n\n\n<p>We\u2019ll program the ESP32 board using Arduino IDE. So, make sure you have the ESP32 add-on installed. Follow the next tutorial if you haven\u2019t already:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-the-esp32-board-in-arduino-ide-windows-instructions\/\">Install the ESP32 Board in Arduino IDE<\/a><\/li>\n<\/ul>\n\n\n\n<p>Additionally, make sure you\u2019re running the latest version of the ESP32 add-on. Go to&nbsp;<strong>Tools&nbsp;<\/strong>&gt;&nbsp;<strong>Board&nbsp;<\/strong>&gt;&nbsp;<strong>Boards Manager,<\/strong>&nbsp;search for&nbsp;<strong>ESP32,&nbsp;<\/strong>and check that you\u2019re running the latest version.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"google-service-account\">2. Google Service Account<\/h2>\n\n\n\n<p>To log data securely to Google Sheets, we&#8217;ll use a Google Service Account. A service account, identified by its unique email address, is a special kind of account. It is typically used by an application or compute workload, like a Compute Engine instance, rather than being associated with a person. You can learn more about a <a href=\"https:\/\/cloud.google.com\/iam\/docs\/service-account-overview\" target=\"_blank\" rel=\"noopener\" title=\"\">service account<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Create a Google Project<\/h3>\n\n\n\n<p>You need to create a Google project and associate a Google service account to that specific project. You can do that on your main Google account or you can choose to do that on another secondary account. As always, we recommend that you use another account just for your IoT and ESP32 projects, and not your main account.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"create-service-account\">Create a Service Account<\/h4>\n\n\n\n<p>1. Go to <a href=\"https:\/\/console.cloud.google.com\/projectselector2\/iam-admin\/settings\" target=\"_blank\" rel=\"noopener\" title=\"\">Google Cloud Console<\/a>.<\/p>\n\n\n\n<p>2. Create a new project or choose an existing project. We&#8217;ll show you how to create a new project.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"992\" height=\"407\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/1-Create-Project.png?resize=992%2C407&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create Google Project\" class=\"wp-image-144937\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/1-Create-Project.png?w=992&amp;quality=100&amp;strip=all&amp;ssl=1 992w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/1-Create-Project.png?resize=300%2C123&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/1-Create-Project.png?resize=768%2C315&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 992px) 100vw, 992px\" \/><\/figure><\/div>\n\n\n<p>3. Give a name to your project. Then, click Create.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"799\" height=\"591\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/2-Google-Cloud-Create-New-Project.png?resize=799%2C591&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create Google Project\" class=\"wp-image-144938\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/2-Google-Cloud-Create-New-Project.png?w=799&amp;quality=100&amp;strip=all&amp;ssl=1 799w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/2-Google-Cloud-Create-New-Project.png?resize=300%2C222&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/2-Google-Cloud-Create-New-Project.png?resize=768%2C568&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 799px) 100vw, 799px\" \/><\/figure><\/div>\n\n\n<p>Your project will be created successfully.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"799\" height=\"591\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/3-Google-Cloud-Project-Created.png?resize=799%2C591&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create google service account\" class=\"wp-image-144939\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/3-Google-Cloud-Project-Created.png?w=799&amp;quality=100&amp;strip=all&amp;ssl=1 799w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/3-Google-Cloud-Project-Created.png?resize=300%2C222&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/3-Google-Cloud-Project-Created.png?resize=768%2C568&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 799px) 100vw, 799px\" \/><\/figure><\/div>\n\n\n<p>4. Now, you need to create a service account for that project. At the left sidebar, click on <strong>Service accounts<\/strong> and then, click on <strong>+ Create Service Account<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"555\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/4-Create-Service-Account.png?resize=1024%2C555&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create google service account 1\" class=\"wp-image-144942\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/4-Create-Service-Account.png?resize=1024%2C555&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/4-Create-Service-Account.png?resize=300%2C163&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/4-Create-Service-Account.png?resize=768%2C416&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/4-Create-Service-Account.png?w=1055&amp;quality=100&amp;strip=all&amp;ssl=1 1055w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p>5. Insert a name for your Service account, then click <strong>Create and Continue<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"984\" height=\"584\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/5-Service-Account-Details.png?resize=984%2C584&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create google service account define set name\" class=\"wp-image-144943\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/5-Service-Account-Details.png?w=984&amp;quality=100&amp;strip=all&amp;ssl=1 984w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/5-Service-Account-Details.png?resize=300%2C178&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/5-Service-Account-Details.png?resize=768%2C456&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 984px) 100vw, 984px\" \/><\/figure><\/div>\n\n\n<p>6. Select the service account role. Select <strong>Owner<\/strong>. Then, click <strong>Continue<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"984\" height=\"539\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/6-Service-Account-Role.png?resize=984%2C539&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create google service account 3\" class=\"wp-image-144944\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/6-Service-Account-Role.png?w=984&amp;quality=100&amp;strip=all&amp;ssl=1 984w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/6-Service-Account-Role.png?resize=300%2C164&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/6-Service-Account-Role.png?resize=768%2C421&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 984px) 100vw, 984px\" \/><\/figure><\/div>\n\n\n<p>7. Finally, click <strong>Done<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"720\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/7-Service-Account-Done.png?resize=800%2C720&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create google service account 2\" class=\"wp-image-144945\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/7-Service-Account-Done.png?w=800&amp;quality=100&amp;strip=all&amp;ssl=1 800w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/7-Service-Account-Done.png?resize=300%2C270&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/7-Service-Account-Done.png?resize=768%2C691&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure><\/div>\n\n\n<p>You successfully create a Service Account. Now, you need to create a Key.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"create-key\">Creating a New Key <\/h4>\n\n\n\n<p>Select the project, click on the three dots icon, and then click on <strong>Manage Keys<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"539\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/8-Service-Account-Actions.png?resize=1024%2C539&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"manage keys google cloud project\" class=\"wp-image-144950\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/8-Service-Account-Actions.png?resize=1024%2C539&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/8-Service-Account-Actions.png?resize=300%2C158&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/8-Service-Account-Actions.png?resize=768%2C405&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/8-Service-Account-Actions.png?w=1230&amp;quality=100&amp;strip=all&amp;ssl=1 1230w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p>Then, create a new key.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"847\" height=\"600\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/9-Create-new-key.png?resize=847%2C600&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"create new key google cloud project\" class=\"wp-image-144951\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/9-Create-new-key.png?w=847&amp;quality=100&amp;strip=all&amp;ssl=1 847w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/9-Create-new-key.png?resize=300%2C213&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/9-Create-new-key.png?resize=768%2C544&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 847px) 100vw, 847px\" \/><\/figure><\/div>\n\n\n<p class=\"download-json\">Then, select <strong>JSON <\/strong>and click <strong>Create<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"554\" height=\"349\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/10-Create-new-key-json.png?resize=554%2C349&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create private key google cloud\" class=\"wp-image-144952\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/10-Create-new-key-json.png?w=554&amp;quality=100&amp;strip=all&amp;ssl=1 554w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/10-Create-new-key-json.png?resize=300%2C189&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 554px) 100vw, 554px\" \/><\/figure><\/div>\n\n\n<p>This will download a JSON file to your computer with the key.<\/p>\n\n\n\n<p>Open the file, and you&#8217;ll get something similar, but with your own details:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"type\": \"service_account\",\n  \"project_id\": \"...\",\n  \"private_key_id\": \"...\",\n  \"private_key\": \"-----BEGIN PRIVATE KEY----- ...................\\n-----END PRIVATE KEY-----\\n\",\n  \"client_email\": \".....\",\n  \"client_id\": \"....\",\n  \"auth_uri\": \"https:\/\/accounts.google.com\/o\/oauth2\/auth\",\n  \"token_uri\": \"https:\/\/oauth2.googleapis.com\/token\",\n  \"auth_provider_x509_cert_url\": \"https:\/\/www.googleapis.com\/oauth2\/v1\/certs\",\n  \"client_x509_cert_url\": \"https:\/\/www.googleapis.com\/...\",\n  \"universe_domain\": \"googleapis.com\"\n}<\/code><\/pre>\n\n\n\n<p>Copy the <strong>project_id<\/strong>, <strong>client_email<\/strong>, <strong>private_key_id<\/strong> and <strong>private_key<\/strong> from the .<em>json<\/em> file because you&#8217;ll need them later.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"enable-google-sheet-api\">Enable Google Sheet API<\/h3>\n\n\n\n<p>Now that you have a project, you need to enable the Google Sheet API for that project. Click on the following link: <a href=\"https:\/\/console.cloud.google.com\/apis\/library\/sheets.googleapis.com\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/console.cloud.google.com\/apis\/library\/sheets.googleapis.com<\/a> and enable Google Sheets API (you need to be on the same account where you created the project).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"818\" height=\"441\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/14-enable-google-sheets-api.png?resize=818%2C441&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"enable Google Sheets API\" class=\"wp-image-144936\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/14-enable-google-sheets-api.png?w=818&amp;quality=100&amp;strip=all&amp;ssl=1 818w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/14-enable-google-sheets-api.png?resize=300%2C162&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/14-enable-google-sheets-api.png?resize=768%2C414&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 818px) 100vw, 818px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"enable-google-drive-api\">Enable Google Drive API<\/h3>\n\n\n\n<p>You also need to enable Google Drive API for your project. Open the following link <a href=\"https:\/\/console.cloud.google.com\/apis\/library\/drive.googleapis.com\">https:\/\/console.cloud.google.com\/apis\/library\/drive.googleapis.com<\/a> and enable the Google Drive API.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"818\" height=\"441\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/15-Enable-Google-Drive-API.png?resize=818%2C441&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"enable Google Drive API\" class=\"wp-image-144935\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/15-Enable-Google-Drive-API.png?w=818&amp;quality=100&amp;strip=all&amp;ssl=1 818w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/15-Enable-Google-Drive-API.png?resize=300%2C162&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/15-Enable-Google-Drive-API.png?resize=768%2C414&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 818px) 100vw, 818px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"install-gsheets-library-arduino\">3. Installing the Arduino Google Sheet Client Library for Arduino devices<\/h2>\n\n\n\n<p>To publish readings to Google Sheets using the Google Service Account, we&#8217;ll use <a href=\"https:\/\/github.com\/mobizt\/ESP-Google-Sheet-Client\/blob\/master\/examples\/Values\/Create_Update_Read\/Create_Update_Read.ino\" target=\"_blank\" rel=\"noopener\" title=\"\">the ESP-Google-Sheet-Client library by Mobitz<\/a>. This library comes with methods to create, read, and delete spreadsheets and write, update, and append data to the spreadsheet file. You can find all the <a href=\"https:\/\/github.com\/mobizt\/ESP-Google-Sheet-Client\/tree\/master\/examples\" target=\"_blank\" rel=\"noopener\" title=\"\">library examples<\/a>.<\/p>\n\n\n\n<p>In the Arduino IDE, go to <strong>Sketch <\/strong>&gt; <strong>Library <\/strong>&gt; <strong>Manage Libraries<\/strong>. Search for <strong>ESP-Google-Sheet-Client<\/strong> and click <strong>Install<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/01\/google-sheet-client-library-install-arduino-ide.png?resize=848%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"install ESP Google Spreadsheet client library arduino ide\" class=\"wp-image-166623\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/01\/google-sheet-client-library-install-arduino-ide.png?w=848&amp;quality=100&amp;strip=all&amp;ssl=1 848w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/01\/google-sheet-client-library-install-arduino-ide.png?resize=300%2C207&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/01\/google-sheet-client-library-install-arduino-ide.png?resize=768%2C531&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 848px) 100vw, 848px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"create-google-spreadsheet\">4. Creating a Google Spreadsheet<\/h2>\n\n\n\n<p>Go to Google Sheets and <a href=\"https:\/\/docs.google.com\/spreadsheets\/u\/0\/?ec=asw-sheets-hero-goto\" target=\"_blank\" rel=\"noopener\" title=\"\">create a new spreadsheet<\/a>. Give a title to your spreadsheet. For example <em>ESP32 Datalogging<\/em>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"942\" height=\"557\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/spreadsheet_id.png?resize=942%2C557&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"spreadsheetid\" class=\"wp-image-144958\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/spreadsheet_id.png?w=942&amp;quality=100&amp;strip=all&amp;ssl=1 942w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/spreadsheet_id.png?resize=300%2C177&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/spreadsheet_id.png?resize=768%2C454&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 942px) 100vw, 942px\" \/><\/figure><\/div>\n\n\n<p>Save the spreadsheet ID. It&#8217;s highlighted in the picture above. The Spreadsheet ID is the last string of characters in the URL for your spreadsheet. For example, in the URL https:\/\/docs.google.com\/spreadsheets\/d\/1aISQE8K79LS5c3vF18qFRcmfDRFn_9nE4nKveWBCtoQ\/edit#gid=0, the spreadsheet ID is <span class=\"rnthl rntliteral\">1aISQE8K79LS5c3vF18qFRcmfDRFn_9nE4nKveWBCtoQ<\/span>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"share-spreadsheet\">5. Share the Spreadsheet with the Service Account<\/h2>\n\n\n\n<p>For you to be able to log data to that spreadsheet using the Google Service Account, as we&#8217;ll do in this tutorial, you need to share the spreadsheet with the service account email. You should get the service account email in the <a href=\"#download-json\" title=\"\">JSON file you downloaded previously<\/a> saved on the <span class=\"rnthl rntliteral\">client_email<\/span> variable.<\/p>\n\n\n\n<p>At the top right corner click on <strong>Share<\/strong>. Paste the service account email and click <strong>Send<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"942\" height=\"557\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/share-with-service-account-f.png?resize=942%2C557&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Share spreadsheet with google service account\" class=\"wp-image-144988\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/share-with-service-account-f.png?w=942&amp;quality=100&amp;strip=all&amp;ssl=1 942w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/share-with-service-account-f.png?resize=300%2C177&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/share-with-service-account-f.png?resize=768%2C454&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 942px) 100vw, 942px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"esp32-bme280\">6. ESP32 with BME280 Circuit<\/h2>\n\n\n\n<p>For this particular example, we&#8217;ll log data from a BME280 sensor. So, you need to wire a BME280 sensor to your ESP32. You can also use any other sensor you&#8217;re familiar with or adjust the code to publish random values if you don&#8217;t have a sensor at hand.<\/p>\n\n\n\n<p class=\"rntbox rntclblue\">Not familiar with the BME280 sensor? Read our getting started guide: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-bme280-arduino-ide-pressure-temperature-humidity\/\" title=\"\">ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic Diagram<\/h3>\n\n\n\n<p>We\u2019re going to use I2C communication with the BME280 sensor module. For that, wire the sensor to the default ESP32&nbsp;SCL (<span class=\"rnthl rntcblue\">GPIO 22<\/span>)&nbsp;and&nbsp;SDA (<span class=\"rnthl rntcgreen\">GPIO 21<\/span>)&nbsp;pins, as shown in the following schematic diagram.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"675\" height=\"670\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=675%2C670&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Wiring to BME280 Schematic Diagram\" class=\"wp-image-99755\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?w=675&amp;quality=100&amp;strip=all&amp;ssl=1 675w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=300%2C298&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 675px) 100vw, 675px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclblue\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-pinout-reference-gpios\/\">ESP32 Pinout Reference: Which GPIO pins should you use?<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"esp32-gsheet-datalogger-arduino-code\">7. ESP32 Datalogging to Google Sheets &#8211; Arduino Sketch<\/h2>\n\n\n\n<p>Copy the following code to the Arduino IDE. Don&#8217;t upload it yet. You need to fill in some details before uploading it to the board.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-datalogging-google-sheets\/\n  \n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n  Adapted from the examples of the Library Google Sheet Client Library for Arduino devices: https:\/\/github.com\/mobizt\/ESP-Google-Sheet-Client\n*\/\n\n#include &lt;Arduino.h&gt;\n#include &lt;WiFi.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;\n#include &lt;Adafruit_BME280.h&gt;\n#include &quot;time.h&quot;\n#include &lt;ESP_Google_Sheet_Client.h&gt;\n\n\/\/ For SD\/SD_MMC mounting helper\n#include &lt;GS_SDHelper.h&gt;\n\n#define WIFI_SSID &quot;REPLACE_WITH_YOUR_SSID&quot;\n#define WIFI_PASSWORD &quot;REPLACE_WITH_YOUR_PASSWORD&quot;\n\n\/\/ Google Project ID\n#define PROJECT_ID &quot;REPLACE_WITH_YOUR_PROJECT_ID&quot;\n\n\/\/ Service Account's client email\n#define CLIENT_EMAIL &quot;REPLACE_WITH_YOUR_CLIENT_EMAIL&quot;\n\n\/\/ Service Account's private key\nconst char PRIVATE_KEY[] PROGMEM = &quot;-----BEGIN PRIVATE KEY-----\\ REPLACE_WITH_YOUR_PRIVATE_KEY\\n-----END PRIVATE KEY-----\\n&quot;;\n\n\/\/ The ID of the spreadsheet where you'll publish the data\nconst char spreadsheetId[] = &quot;YOUR_SPREADSHEET_ID&quot;;\n\n\/\/ Timer variables\nunsigned long lastTime = 0;  \nunsigned long timerDelay = 30000;\n\n\/\/ Token Callback function\nvoid tokenStatusCallback(TokenInfo info);\n\n\/\/ BME280 I2C\nAdafruit_BME280 bme;\n\/\/ Variables to hold sensor readings\nfloat temp;\nfloat hum;\nfloat pres;\n\n\/\/ NTP server to request epoch time\nconst char* ntpServer = &quot;pool.ntp.org&quot;;\n\n\/\/ Variable to save current epoch time\nunsigned long epochTime; \n\n\/\/ Function that gets current epoch time\nunsigned long getTime() {\n  time_t now;\n  struct tm timeinfo;\n  if (!getLocalTime(&amp;timeinfo)) {\n    \/\/Serial.println(&quot;Failed to obtain time&quot;);\n    return(0);\n  }\n  time(&amp;now);\n  return now;\n}\n\nvoid setup(){\n\n    Serial.begin(115200);\n    Serial.println();\n    Serial.println();\n\n    \/\/Configure time\n    configTime(0, 0, ntpServer);\n\n    \/\/ Initialize BME280 sensor \n    if (!bme.begin(0x76)) {\n      Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\n      while (1);\n    }\n\n    GSheet.printf(&quot;ESP Google Sheet Client v%s\\n\\n&quot;, ESP_GOOGLE_SHEET_CLIENT_VERSION);\n\n    \/\/ Connect to Wi-Fi\n    WiFi.setAutoReconnect(true);\n    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n  \n    Serial.print(&quot;Connecting to Wi-Fi&quot;);\n    while (WiFi.status() != WL_CONNECTED) {\n      Serial.print(&quot;.&quot;);\n      delay(1000);\n    }\n    Serial.println();\n    Serial.print(&quot;Connected with IP: &quot;);\n    Serial.println(WiFi.localIP());\n    Serial.println();\n\n    \/\/ Set the callback for Google API access token generation status (for debug only)\n    GSheet.setTokenCallback(tokenStatusCallback);\n\n    \/\/ Set the seconds to refresh the auth token before expire (60 to 3540, default is 300 seconds)\n    GSheet.setPrerefreshSeconds(10 * 60);\n\n    \/\/ Begin the access token generation for Google API authentication\n    GSheet.begin(CLIENT_EMAIL, PROJECT_ID, PRIVATE_KEY);\n}\n\nvoid loop(){\n    \/\/ Call ready() repeatedly in loop for authentication checking and processing\n    bool ready = GSheet.ready();\n\n    if (ready &amp;&amp; millis() - lastTime &gt; timerDelay){\n        lastTime = millis();\n\n        FirebaseJson response;\n\n        Serial.println(&quot;\\nAppend spreadsheet values...&quot;);\n        Serial.println(&quot;----------------------------&quot;);\n\n        FirebaseJson valueRange;\n\n        \/\/ New BME280 sensor readings\n        temp = bme.readTemperature();\n        \/\/temp = 1.8*bme.readTemperature() + 32;\n        hum = bme.readHumidity();\n        pres = bme.readPressure()\/100.0F;\n        \/\/ Get timestamp\n        epochTime = getTime();\n\n        valueRange.add(&quot;majorDimension&quot;, &quot;COLUMNS&quot;);\n        valueRange.set(&quot;values\/[0]\/[0]&quot;, epochTime);\n        valueRange.set(&quot;values\/[1]\/[0]&quot;, temp);\n        valueRange.set(&quot;values\/[2]\/[0]&quot;, hum);\n        valueRange.set(&quot;values\/[3]\/[0]&quot;, pres);\n\n        \/\/ For Google Sheet API ref doc, go to https:\/\/developers.google.com\/sheets\/api\/reference\/rest\/v4\/spreadsheets.values\/append\n        \/\/ Append values to the spreadsheet\n        bool success = GSheet.values.append(&amp;response \/* returned response *\/, spreadsheetId \/* spreadsheet Id to append *\/, &quot;Sheet1!A1&quot; \/* range to append *\/, &amp;valueRange \/* data range to append *\/);\n        if (success){\n            response.toString(Serial, true);\n            valueRange.clear();\n        }\n        else{\n            Serial.println(GSheet.errorReason());\n        }\n        Serial.println();\n        Serial.println(ESP.getFreeHeap());\n    }\n}\n\nvoid tokenStatusCallback(TokenInfo info){\n    if (info.status == token_status_error){\n        GSheet.printf(&quot;Token info: type = %s, status = %s\\n&quot;, GSheet.getTokenType(info).c_str(), GSheet.getTokenStatus(info).c_str());\n        GSheet.printf(&quot;Token error: %s\\n&quot;, GSheet.getTokenError(info).c_str());\n    }\n    else{\n        GSheet.printf(&quot;Token info: type = %s, status = %s\\n&quot;, GSheet.getTokenType(info).c_str(), GSheet.getTokenStatus(info).c_str());\n    }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/ESP32_Google_Sheets.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Insert your network credentials on the following variables.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define WIFI_SSID \"REPLACE_WITH_YOUR_SSID\"\n#define WIFI_PASSWORD \"REPLACE_WITH_YOUR_PASSWORD\"<\/code><\/pre>\n\n\n\n<p>Insert your project ID, your client email, and your private key (you can find these details on the JSON file you downloaded in the previous steps).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Google Project ID\n#define PROJECT_ID \"REPLACE_WITH_YOUR_PROJECT_ID\"\n\n\/\/ Service Account's client email\n#define CLIENT_EMAIL \"REPLACE_WITH_YOUR_CLIENT_EMAIL\"\n\n\/\/ Service Account's private key\nconst char PRIVATE_KEY&#091;] PROGMEM = \"-----BEGIN PRIVATE KEY-----\\ REPLACE_WITH_YOUR_PRIVATE_KEY\\n-----END PRIVATE KEY-----\\n\";<\/code><\/pre>\n\n\n\n<p>Finally, insert the ID of the spreadsheet you want to publish your data.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ The ID of the spreadsheet where you'll publish the data\nconst char spreadsheetId&#091;] = \"YOUR_SPREADSHEET_ID\";<\/code><\/pre>\n\n\n\n<p class=\"has-text-color has-link-color wp-elements-175ea1b6a8724fa02b5f423b425738dd\" style=\"color:#940a0a\"><strong>Note: if your Google Sheets is not in English language, you might need to change <span class=\"rnthl rntliteral\">Sheet1<\/span> with the corresponding in your language<\/strong> <strong>on the following line.<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>bool success = GSheet.values.append(&amp;response \/* returned response *\/, spreadsheetId \/* spreadsheet Id to append *\/, \"<strong>Sheet1<\/strong>!A1\" \/* range to append *\/, &amp;valueRange \/* data range to append *\/);<\/code><\/pre>\n\n\n\n<p>You can now upload the code to your ESP32 board.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>Continue reading to learn how the code works, or skip to the <a href=\"#demonstration\" title=\"\">Demonstration <\/a>section.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Including Libraries<\/h4>\n\n\n\n<p>First, include the required libraries. We need the <span class=\"rnthl rntliteral\">WiFi<\/span> library to connect our board to the internet, the <span class=\"rnthl rntliteral\">Adafruit_sensor<\/span> and <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> to interface with the BME280, the <span class=\"rnthl rntliteral\">time.h<\/span> library to get the timestamp and finally, the <span class=\"rnthl rntliteral\">ESP_Google_Sheet_Client<\/span> to interface the ESP32 with Google Sheets.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Network Credentials<\/h4>\n\n\n\n<p>Insert your network credentials on the following variables.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define WIFI_SSID \"REPLACE_WITH_YOUR_SSID\"\n#define WIFI_PASSWORD \"REPLACE_WITH_YOUR_PASSWORD\"<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Project Details<\/h4>\n\n\n\n<p>Insert your project ID, service account email, and account private key. All these details can be found on the JSON file you downloaded previously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Google Project ID\n#define PROJECT_ID \"REPLACE_WITH_YOUR_PROJECT_ID\"\n\n\/\/ Service Account's client email\n#define CLIENT_EMAIL \"REPLACE_WITH_YOUR_CLIENT_EMAIL\"\n\n\/\/ Service Account's private key\nconst char PRIVATE_KEY&#091;] PROGMEM = \"-----BEGIN PRIVATE KEY-----\\ REPLACE_WITH_YOUR_PRIVATE_KEY\\n-----END PRIVATE KEY-----\\n\";<\/code><\/pre>\n\n\n\n<p>Insert the google spreadsheet id on the following variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char spreadsheetId&#091;] = \"YOUR_SPREADSHEET_ID\";<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">BME280 Variables<\/h4>\n\n\n\n<p>Create an instance for the BME280 called <span class=\"rnthl rntliteral\">bme<\/span> and create variables to save temperature, humidity, and pressure.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ BME280 I2C\nAdafruit_BME280 bme;\n\/\/ Variables to hold sensor readings\nfloat temp;\nfloat hum;\nfloat pres;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Timestamp Variables<\/h4>\n\n\n\n<p>We create a variable with the ntp server we&#8217;ll request time from and a variable to save the current epoch time.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ NTP server to request epoch time\nconst char* ntpServer = \"pool.ntp.org\";\n\n\/\/ Variable to save current epoch time\nunsigned long epochTime; <\/code><\/pre>\n\n\n\n<p>We also create a function to return the current epoch time called <span class=\"rnthl rntliteral\">getTime()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Function that gets current epoch time\nunsigned long getTime() {\n  time_t now;\n  struct tm timeinfo;\n  if (!getLocalTime(&amp;timeinfo)) {\n    \/\/Serial.println(\"Failed to obtain time\");\n    return(0);\n  }\n  time(&amp;now);\n  return now;\n}<\/code><\/pre>\n\n\n\n<p class=\"rntbox rntclgreen\">Learn more about epoch time with the ESP32: <a href=\"https:\/\/randomnerdtutorials.com\/epoch-unix-time-esp32-arduino\/\">Get Epoch\/Unix Time with the ESP32 (Arduino)<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">setup()<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize the Serial Monitor for debugging purposes.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);\nSerial.println();\nSerial.println();<\/code><\/pre>\n\n\n\n<p>Configure the time.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Configure time\nconfigTime(0, 0, ntpServer);<\/code><\/pre>\n\n\n\n<p>Initialize the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Initialize BME280 sensor \nif (!bme.begin(0x76)) {\n  Serial.println(\"Could not find a valid BME280 sensor, check wiring!\");\n  while (1);\n}<\/code><\/pre>\n\n\n\n<p>Connect the ESP32 to your local network.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Connect to Wi-Fi\nWiFi.setAutoReconnect(true);\nWiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n  \nSerial.print(\"Connecting to Wi-Fi\");\nwhile (WiFi.status() != WL_CONNECTED) {\n  Serial.print(\".\");\n  delay(1000);\n}\nSerial.println();\nSerial.print(\"Connected with IP: \");\nSerial.println(WiFi.localIP());\nSerial.println();<\/code><\/pre>\n\n\n\n<p>Then, the following lines configure and initiate the authentication process for accessing Google APIs, including setting up a callback for token generation status, specifying a token refresh interval, and starting the generation of an access token with the relevant authentication credentials (<span class=\"rnthl rntliteral\">CLIENT_EMAIL<\/span>, <span class=\"rnthl rntliteral\">PROJECT_ID<\/span>, and <span class=\"rnthl rntliteral\">PRIVATE_KEY<\/span> that you&#8217;ve defined previously).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Set the callback for Google API access token generation status (for debug only)\nGSheet.setTokenCallback(tokenStatusCallback);\n\n\/\/ Set the seconds to refresh the auth token before expire (60 to 3540, default is 300 seconds)\nGSheet.setPrerefreshSeconds(10 * 60);\n\n\/\/ Begin the access token generation for Google API authentication\nGSheet.begin(CLIENT_EMAIL, PROJECT_ID, PRIVATE_KEY);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">loop()<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span>, you need to call the following line so that it constantly checks the authentication.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>bool ready = GSheet.ready();<\/code><\/pre>\n\n\n\n<p>Then, we&#8217;ll periodically publish sensor readings to Google Sheets. You can adjust the interval on the <span class=\"rnthl rntliteral\">timerDelay<\/span> variable defined at the start of the code.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (ready &amp;&amp; millis() - lastTime &gt; timerDelay){<\/code><\/pre>\n\n\n\n<p>We create a JSON object called <span class=\"rnthl rntliteral\">valueRange<\/span> where we&#8217;ll add our data. The Google Sheets Client library we&#8217;re using with the ESP32 uses the <span class=\"rnthl rntliteral\">FirebaseJson<\/span> library to handle JSON objects. To keep compatibility with other examples in the library, we&#8217;re also using that library.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>FirebaseJson valueRange;<\/code><\/pre>\n\n\n\n<p>We then get new BME280 readings and a corresponding timestamp.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ New BME280 sensor readings\ntemp = bme.readTemperature();\n\/\/temp = 1.8*bme.readTemperature() + 32;\nhum = bme.readHumidity();\npres = bme.readPressure()\/100.0F;\n\/\/ Get timestamp\nepochTime = getTime();<\/code><\/pre>\n\n\n\n<p>These values are added to a <span class=\"rnthl rntliteral\">FirebaseJson<\/span> object (<span class=\"rnthl rntliteral\">valueRange<\/span>).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>valueRange.add(\"majorDimension\", \"COLUMNS\");\nvalueRange.set(\"values\/&#091;0]\/&#091;0]\", epochTime);\nvalueRange.set(\"values\/&#091;1]\/&#091;0]\", temp);\nvalueRange.set(\"values\/&#091;2]\/&#091;0]\", hum);\nvalueRange.set(\"values\/&#091;3]\/&#091;0]\", pres);<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">valueRange<\/span> object is configured to have a <span class=\"rnthl rntliteral\">&#8220;COLUMNS&#8221;<\/span> major dimension, indicating that the data will be organized column-wise. The timestamp will be located at the first column, first row; the temperature in the second column, first row, etc. If you want to organize in rows, you can pass <span class=\"rnthl rntliteral\">&#8220;ROWS&#8221;<\/span> as an argument instead.<\/p>\n\n\n\n<p>Then, append this data to a specific sheet (Sheet1) starting at cell A1 in a Google Spreadsheet identified by its <span class=\"rnthl rntliteral\">spreadsheetId<\/span>. The values in <span class=\"rnthl rntliteral\">valueRange<\/span> are mapped to specific cells in the sheet, such as the timestamp in column A and the sensor readings in subsequent columns.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Append values to the spreadsheet\nbool success = GSheet.values.append(&amp;response \/* returned response *\/, spreadsheetId \/* spreadsheet Id to append *\/, \"Sheet1!A1\" \/* range to append *\/, &amp;valueRange \/* data range to append *\/);\nif (success){\n    response.toString(Serial, true);\n    valueRange.clear();\n}\nelse{\n    Serial.println(GSheet.errorReason());\n}<\/code><\/pre>\n\n\n\n<p class=\"has-text-color has-link-color wp-elements-175ea1b6a8724fa02b5f423b425738dd\" style=\"color:#940a0a\"><strong>Note: if your Google Sheets is not in English language, you might need to change <span class=\"rnthl rntliteral\">Sheet1<\/span> with the corresponding in your language<\/strong> <strong>on the following line.<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>bool success = GSheet.values.append(&amp;response \/* returned response *\/, spreadsheetId \/* spreadsheet Id to append *\/, \"<strong>Sheet1<\/strong>!A1\" \/* range to append *\/, &amp;valueRange \/* data range to append *\/);<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"demonstration\">Demonstration<\/h2>\n\n\n\n<p>After uploading the code to the ESP32, open the Serial Monitor to check the process.<\/p>\n\n\n\n<p>The ESP32 should successfully connect to your Wi-Fi network and after 30 seconds, it should publish its first reading.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"747\" height=\"664\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/01\/ESP32-publish-to-google-sheets.png?resize=747%2C664&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Publishing to Google Sheets Serial Monitor\" class=\"wp-image-166625\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/01\/ESP32-publish-to-google-sheets.png?w=747&amp;quality=100&amp;strip=all&amp;ssl=1 747w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/01\/ESP32-publish-to-google-sheets.png?resize=300%2C267&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 747px) 100vw, 747px\" \/><\/figure><\/div>\n\n\n<p>Open the spreadsheet where you&#8217;re publishing the values. You should see new values being published in real-time. The first column contains the epoch time, then the temperature in Celsius degrees, the humidity, and finally the pressure in hPa.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"998\" height=\"695\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-datalogging-google-sheets.png?resize=998%2C695&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Data Published to Google Spreadsheet\" class=\"wp-image-144969\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-datalogging-google-sheets.png?w=998&amp;quality=100&amp;strip=all&amp;ssl=1 998w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-datalogging-google-sheets.png?resize=300%2C209&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-datalogging-google-sheets.png?resize=768%2C535&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 998px) 100vw, 998px\" \/><\/figure><\/div>\n\n\n<p>We&#8217;re using the timestamp in epoch time. To convert it to a readable format, you can simply use the <a href=\"https:\/\/support.google.com\/docs\/answer\/13193461?hl=en\" target=\"_blank\" rel=\"noopener\" title=\"\">EPOCHTODATE() function<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>We hope you&#8217;ve found this project useful. As an example, we&#8217;ve shown you how to log data from a BME280 sensor, but you easily modify this project to use any other sensor. We have <a href=\"https:\/\/randomnerdtutorials.com\/esp32-guides-sensors-modules\/\" title=\"\">tutorials for more than 25 sensors with the ESP32<\/a>.<\/p>\n\n\n\n<p>The <a href=\"https:\/\/github.com\/mobizt\/ESP-Google-Sheet-Client\" target=\"_blank\" rel=\"noopener\" title=\"\">Arduino Google Sheets Client library<\/a> has many other features and useful methods that might be handy for your project. For example, instead of you having to create the spreadsheet manually, the library comes with a method to <a href=\"https:\/\/github.com\/mobizt\/ESP-Google-Sheet-Client\/tree\/master\/examples\/Spreadsheets\" target=\"_blank\" rel=\"noopener\" title=\"\">automatically create the spreadsheet<\/a>. It can also read, update, and append data to the spreadsheet. We recommend taking a look at the <a href=\"https:\/\/github.com\/mobizt\/ESP-Google-Sheet-Client\/tree\/master\/examples\" target=\"_blank\" rel=\"noopener\" title=\"\">library examples<\/a> to have an idea of what this powerful library can do.<\/p>\n\n\n\n<p>We also have a similar project, but using a different approach. Instead of using a Google Service Account, we use IFTTT services: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-publish-sensor-readings-to-google-sheets\/\" title=\"\">ESP32 Publish Sensor Readings to Google Sheets using IFTTT<\/a>. This method is more limited, but might also be a good option depending on your project requirements.<\/p>\n\n\n\n<p class=\"rntbox rntclblue\">Looking for other data logging methods? Read: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-how-to-log-data\/\" title=\"\">ESP32: How to Log Data (9 Different Ways)<\/a><\/p>\n\n\n\n<p>Learn more about the ESP32 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE (eBook)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/build-web-servers-esp32-esp8266-ebook\/\">Build Web Servers with ESP32 and ESP8266 (eBook)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/firebase-esp32-esp8266-ebook\/\">Firebase Web App with ESP32 and ESP8266 (eBook)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/smart-home-ebook\/\">SMART HOME with Raspberry Pi, ESP32, and ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">Free ESP32 Projects and Tutorials\u2026<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this project, you&#8217;ll learn how to log data to Google Sheets with the ESP32 securely and reliably using a Google Service Account and Google Sheets API. We&#8217;ll use the &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 Datalogging to Google Sheets (using Google Service Account)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-datalogging-google-sheets\/#more-144933\" aria-label=\"Read more about ESP32 Datalogging to Google Sheets (using Google Service Account)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":144999,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[276,281,277,299,264],"tags":[],"class_list":["post-144933","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32","category-esp32-project","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/12\/ESP32-Publish-Google-sheets.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/144933","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=144933"}],"version-history":[{"count":18,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/144933\/revisions"}],"predecessor-version":[{"id":166626,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/144933\/revisions\/166626"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/144999"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=144933"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=144933"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=144933"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}