Explore all Wifi open source software, libraries, packages, source code, cloud functions and APIs.

Popular New Releases in Wifi

esp8266_deauther

Version 2.6.1

itlwm

v2.1.0 stable

wifi-password

Release 1.1.1

TinyCheck

New version of TinyCheck with MISP implementation!

VPNHotspot

v2.13.5

Popular Libraries in Wifi

esp8266_deauther

by SpacehuhnTech doticoncdoticon

star image 8891 doticonNOASSERTION

Affordable WiFi hacking platform for testing and learning

howmanypeoplearearound

by schollz doticonpythondoticon

star image 6501 doticonMIT

Count the number of people around you :family_man_man_boy: by monitoring wifi signals :satellite:

itlwm

by OpenIntelWireless doticoncdoticon

star image 5394 doticonNOASSERTION

Intel Wi-Fi Drivers for macOS

whereami

by kootenpv doticonpythondoticon

star image 4569 doticonAGPL-3.0

Uses WiFi signals :signal_strength: and machine learning to predict where you are

create_ap

by oblique doticonshelldoticon

star image 4105 doticonBSD-2-Clause

[NOT MAINTAINED] This script creates a NATed or Bridged WiFi Access Point.

wifijammer

by DanMcInerney doticonpythondoticon

star image 3258 doticon

Continuously jam all wifi clients/routers

wifite2

by derv82 doticonpythondoticon

star image 3244 doticonGPL-2.0

Rewrite of the popular wireless network auditor, "wifite"

FreeWifi

by kylemcdonald doticonpythondoticon

star image 2684 doticonNOASSERTION

How to get free wifi.

SpoofMAC

by feross doticonpythondoticon

star image 2624 doticon

:briefcase: Change your MAC address for debugging

Trending New libraries in Wifi

itlwm

by OpenIntelWireless doticoncdoticon

star image 5394 doticonNOASSERTION

Intel Wi-Fi Drivers for macOS

wifi-password

by sdushantha doticonpythondoticon

star image 2129 doticonMIT

Quickly fetch your WiFi password and if needed, generate a QR code of your WiFi to allow phones to easily connect

TinyCheck

by KasperskyLab doticonpythondoticon

star image 1870 doticonNOASSERTION

TinyCheck allows you to easily capture network communications from a smartphone or any device which can be associated to a Wi-Fi access point in order to quickly analyze them. This can be used to check if any suspect or malicious communication is outgoing from a smartphone, by using heuristics or specific Indicators of Compromise (IoCs). In order to make it working, you need a computer with a Debian-like operating system and two Wi-Fi interfaces. The best choice is to use a Raspberry Pi (2+) a Wi-Fi dongle and a small touch screen. This tiny configuration (for less than $50) allows you to tap any Wi-Fi device, anywhere.

HeliPort

by OpenIntelWireless doticonswiftdoticon

star image 899 doticonBSD-3-Clause

Intel Wi-Fi Client for itlwm

openwifipass

by seemoo-lab doticonpythondoticon

star image 641 doticonGPL-3.0

An open source implementation of Apple's Wi-Fi Password Sharing protocol in Python.

adapter

by AppleIntelWifi doticoncdoticon

star image 495 doticonNOASSERTION

Kext providing initial support for Intel wireless devices

Pi.Alert

by pucherot doticonjavascriptdoticon

star image 337 doticonGPL-3.0

WIFI / LAN intruder detector. Check the devices connected and alert you with unknown devices. It also warns of the disconnection of "always connected" devices

h4rpy

by MS-WEB-BN doticonshelldoticon

star image 214 doticon

Automated WPA/WPA2 PSK attack tool.

rtl8814au

by aircrack-ng doticoncdoticon

star image 200 doticonNOASSERTION

Realtek rtl8814au driver

Top Authors in Wifi

1

kevva

10 Libraries

star icon882

2

OnionIoT

6 Libraries

star icon27

3

googlearchive

6 Libraries

star icon2407

4

derhuerst

6 Libraries

star icon14

5

armtronix

5 Libraries

star icon31

6

cilynx

5 Libraries

star icon801

7

openwisp

5 Libraries

star icon650

8

morrownr

5 Libraries

star icon432

9

balena-io-playground

5 Libraries

star icon67

10

ARMmbed

5 Libraries

star icon56

1

10 Libraries

star icon882

2

6 Libraries

star icon27

3

6 Libraries

star icon2407

4

6 Libraries

star icon14

5

5 Libraries

star icon31

6

5 Libraries

star icon801

7

5 Libraries

star icon650

8

5 Libraries

star icon432

9

5 Libraries

star icon67

10

5 Libraries

star icon56

Trending Kits in Wifi

A wifi library is a collection of pre-written code and functions. Developers can use it to interact with wifi networks and devices in their applications. These libraries provide an interface to perform various wifi-related tasks. It includes scanning for networks, connecting to access points, and retrieving network information. It helps in managing network configurations.  

 

In the node.js ecosystem, there are several wifi libraries available. It helps cater to different needs and requirements. These libraries cover various functionalities, including networking, security, access point management, and more.  

 

When exploring these libraries, developers will find various features and capabilities. Some libraries offer straightforward functions for basic wifi interactions. But others provide solutions with encryption protocols, signal-level monitoring, and event systems.  

 

Developers can follow a few tips to find the best wifi library for a specific use case. Reading reviews and feedback can provide insights into the library's reliability and performance. Additionally, comparing the side-by-side features can help make an informed decision.  

 

The usage of a wifi library can vary depending on the project's requirements. It can be as simple as creating a web application. It connects to a wifi network or is as complex as developing an IoT platform. It interacts with many hardware devices over wifi.  

 

Developers should follow the setup instructions provided by the library documentation. They should familiarize themselves with the library's API and understand specific requirements. Additionally, the code samples can help learn how to use its features.  

 

When writing about using a wifi library in a project, you should discuss its purpose and features. Emphasize the need for researching and comparing libraries to find the suitable one. Provide practical advice on using the library and highlight the unique aspects. It will make the chosen library a valuable tool for developers.  

wifi-password:  

  • It helps in retrieving the password of the current wifi network.  
  • It supports accessing the stored wifi password from the operating system.  
  • Wifi password retrieval applications, network security tools, and wifi credential management.  

node-wifi:  

  • It helps in managing wifi networks programmatically.  
  • It supports connecting to wifi networks and scanning for available networks. It helps in getting the current connection status.  
  • IoT devices, automated network management systems, and network monitoring tools.  

wireless-tools:  

  • It helps in interacting with wireless network interfaces.  
  • It supports scanning for networks, connecting to networks, and configuring wireless settings.  
  • Network configuration utilities, wireless network management tools, and wifi hotspot management.  

wifi-location:  

  • It helps determine a wifi network's location based on its BSSID.  
  • It supports mapping BSSIDs to physical locations using wifi geolocation databases.  
  •  Wi-Fi-based geolocation services, asset tracking systems, and location-aware applications.  

wifi-name:  

  • It helps in getting the current SSID of the connected wifi network.  
  • It supports retrieving the network name to which the device is currently connected.  
  • Wifi status indicators, network monitoring applications, and wifi profile management.  

node-wifi-scanner:  

  • It helps in scanning and discovering wifi networks in the vicinity.  
  • It supports retrieving information about available networks. It includes SSID, signal strength, and encryption type.  
  • Wifi analyzer tools, network mapping applications, and location-based services. 

node-wifi-tools:  

  • It helps in managing and troubleshooting wifi connections.  
  • It supports features like getting network information. It helps in connecting to networks and performing network diagnostics.  
  • Wifi troubleshooting utilities, network monitoring applications, wifi connection managers.  

wifi-ap:  

  • It helps create a wifi access point (AP) using a Node.js application.  
  • It supports configuring and managing a software-based wifi access point.  
  •  Wifi hotspot applications, wireless network simulation, IoT device provisioning.  

FAQ  

1. What is the nodejs wifi library, and how does it work?  

The nodejs wifi library is a collection of code and functions. It enables developers to interact with wifi networks and devices using Node.js. It provides an interface to perform various wifi-related tasks. These tasks can be scanning for available networks and connecting to access points. It also helps in retrieving network information and managing network configurations. The library works by utilizing the underlying operating system's wifi capabilities. It provides a simplified API for developers to work with.  

 

2. How do you use the wifi interface with this library?  

The wifi interface allows developers to interact with wifi networks and devices. To use the wifi interface, developers can use the functions to perform scanning. It also helps connect to a specific network and disconnect from a network. It helps in retrieving information about the current network connection. Developers can manage wifi interactions within their applications by using the wifi interface.  

 

3. What type of JavaScript runtime environment is required to use the wifi library?  

The nodejs wifi library is compatible with any JavaScript runtime environment. Node.js is a runtime built on Chrome's V8 JavaScript engine. It allows JavaScript code on the server side. To use the nodejs wifi library, developers must have a runtime environment. It supports Node.js installed on its system.  

 

4. How can access points be configured using the nodejs wifi library?  

With the nodejs wifi library, access points can be configured. Developers can use the library's functions to connect to a specific access point. It provides the necessary credentials or security information. Additionally, the library allows for managing and manipulating access point configurations. It includes changing the network name (SSID), password, encryption protocols, and other settings. This flexibility enables developers to automate access point configurations within their applications.  

 

5. Is it possible to get a remote IP address from a remote client using this library?  

Yes, it is possible to retrieve a remote client's IP address using the nodejs wifi library. Developers can connect with a remote client over wifi by utilizing the functions. It helps retrieve information about the client, including the remote IP address. This can be useful for various applications, such as tracking client connections. It helps enforce access restrictions or analyze network traffic patterns.  

 

6. What are the advantages of using WebSocket with the wifi library over other protocols?  

WebSocket is a communication protocol. It offers full-duplex communication channels over a single TCP connection. WebSocket offers several advantages over other protocols when used with the wifi library. WebSocket enables real-time, bidirectional communication between the client and the server. It allows instant data updates and notifications. Additionally, WebSocket connections have a lower overhead compared to traditional HTTP connections. It results in reduced latency and improved performance.  

 

Furthermore, WebSocket supports persistent connections, eliminating the need for repeated connection establishment. It can be beneficial for scenarios involving frequent data transmission and real-time updates. WebSocket enhances the capabilities of the nodejs wifi library. It provides a reliable and efficient communication channel for wifi-enabled applications. 

Trending Discussions on Wifi

Puppeteer scrape value generated in javaScript

Android Studio BumbleBee pair wifi not working

Android Studio Bumblebee Wifi pairing Issue

Is the Android Wifi-API really so broken on Android 10+?

Should macOS daemons be made from the "Command Line Tool" Xcode template?

How to rebuild epoll package in electron?

How to get a response from the async write function in capacitor-community / bluetooth-le

Android Studio Disconnects From Physical Device

Winsock sendto returns error 10049 (WSAEADDRNOTAVAIL) for broadcast address after network adapter is disabled or physically disconnected

Compress & Upload large videos to Google cloud storage using Flutter/Dart

QUESTION

Puppeteer scrape value generated in javaScript

Asked 2022-Apr-17 at 10:16

How do I scrape a value that is generated within Javascript. I have been trying to figure this out for a few days and now I'm stuck. I have the page login stuff working. The page looks like this in a browser and I want to extract the SoC% value and nothing else. In this example the value is 92.16%
enter image description here

This page will auto update every 10 minute.

I can see the part of the JS that returns the value but I don't know how to scrape this value into a variable in my script.

1if ('battery_soc' in d.last) {
2  content+="<td>"+d.last.battery_soc+"%</td>";
3}
4else {
5   content+="<td class='hidden-xs'>—</td>";
6}

Here is the full html page if that helps.

1if ('battery_soc' in d.last) {
2  content+="<td>"+d.last.battery_soc+"%</td>";
3}
4else {
5   content+="<td class='hidden-xs'>—</td>";
6}<!DOCTYPE html>
7<html>
8    <head>
9        <meta charset="utf-8">
10        <meta http-equiv="X-UA-Compatible" content="IE=9;IE=10;IE=Edge,chrome=1" />
11        <meta name="viewport" content="width=device-width, initial-scale=1" />
12        <meta name="Description" content="Select.Live is web based SCADA for SP Pro inverters and its system" />
13        <meta name="Author" content="Selctronic Australia Pty Ltd" />
14        <title>Select.Live Portal | Selectronic Australia</title>
15        <link href="https://fonts.googleapis.com/css?family=Titillium+Web" rel="stylesheet">
16        <link href="/css/bootstrap.min.css" rel="stylesheet" />
17        <link href="/css/zebra_datepicker.min.css" rel="stylesheet" />
18        <link href="/css/ad-style.css" rel="stylesheet" />
19        <script src="/js/jquery.min.js"></script>
20        <script src="/js/bootstrap.min.js"></script>
21        <script src="/js/zebra_datepicker.min.js"></script>
22        <script src="/js/user_geolocation.js"></script>
23        <script type="text/javascript">
24         var geocodeKey = "";
25        </script>
26    </head>
27
28    <body>
29    <div class="ad-header">
30        <button type="button" class="side-toggle left hidden-sm hidden-md hidden-lg" data-toggle="open">
31            <span class="bar"></span> <span class="bar"></span> <span class="bar"></span>
32        </button>
33        <div class="header-logo left"></div>
34        <div class="clear"></div>
35    </div>
36
37    
38<div class="section">
39
40  <div align="center" class="side-menu">
41    <ul>
42      <li><a href="/systems"><span class="glyphicon glyphicon-list"></span><span class="hideit">Systems</span></a></li>
43      <li><a href="/myprofile"><span class="glyphicon glyphicon-user"></span><span class="hideit">My Profile</span></a></li>
44      <li><a href="/logout"><span class="glyphicon glyphicon-log-out"></span><span class="hideit">Logout</span></a></li>
45    </ul>
46  </div>
47  <script type="text/javascript">
48    $(".side-menu li:nth-child(1)").addClass("active");
49  </script>
50
51
52  <div class="main-content container-fluid">
53    <div class="row">
54      <div id="map" style="height: 300px;"></div>
55    </div>
56
57    <!-- My Systems -->
58    <div class="row">
59      <div class="col col-md-12 main-content-padding">
60        <div class="main-content-inner">
61          <div class="main-content-header">
62            <h3>My Systems</h3>
63          </div>
64          <div class="main-content-body">
65            <table id="ownerSystems" class="table table-hover table-responsive table-striped">
66              <thead>
67                <tr>
68                  <th>System Name</th>
69                  <th>Status</th>
70                  <th>SoC</th>
71                  <th class="hidden-xs">Production</th>
72                  <th class="hidden-xs">Purchased</th>
73                  <th class="hidden-xs">Consumption</th>
74                </tr>
75              </thead>
76              <tbody>
77              </tbody>
78            </table>
79            <div align="right"> <a href="#" class="add_system btn btn-primary btn-lg"><span class="glyphicon glyphicon-plus"></span> Add a System</a> </div>
80          </div>
81        </div>
82      </div>
83    </div>
84
85    <!-- Other systems (have installer access to these) 0 -->
86    <div id="otherSystems" class="row hidden" >
87<div class="col col-md-12 main-content-padding">
88        <div class="main-content-inner">
89          <div class="main-content-header">
90            <h3>Other Systems</h3>
91          </div>
92          <div class="main-content-body">
93            <table id="installerSystems" class="table table-hover table-responsive table-striped">
94              <thead>
95                <tr>
96                  <th>System Name</th>
97                  <th>Status</th>
98                  <th>SoC</th>
99                  <th class="hidden-xs">Production</th>
100                  <th class="hidden-xs">Purchased</th>
101                  <th class="hidden-xs">Consumption</th>
102                </tr>
103              </thead>
104              <tbody>
105              </tbody>
106            </table>
107          </div>
108        </div>
109      </div>
110    </div>
111
112    <div class="clear"></div>
113  </div>
114</div>
115<div class="overlay">
116  <div class="container">
117    <div class="row">
118      <div class="col-sm-12">
119        <div class="overlay_content" style="overflow-y: auto;">
120          <div class="overlay_header">
121            <div class="right"> <a href="#" class="overlay_close"><span class="glyphicon glyphicon-remove"></span></a> </div>
122            <div class="clearfix"></div>
123          </div>
124          <div class="overlay_body">
125            <h3>Add a new System to your profile</h3>
126            <p>Connect your Select.Live Device to your SP PRO and set it up so that it is connected to the Internet.</p>
127            <p>Please find the Device ID and Serial number on the LCD screen of your Select.Live Device as shown in the example,
128            and copy those details into the form below.
129            </p>
130            <img src="images/LCD_claim_Selectronic.png">
131            <form id="claim_form" style="clear:both;">
132              <div class="form-group">
133                <label for="claim_code">Device ID</label>
134                <input type="text" id="claim_code" class="form-control" name="devhash" placeholder="id">
135              </div>
136              <div class="form-group">
137                <label for="claim_serial">Serial</label>
138                <input type="text" id="claim_serial" class="form-control" name="serialnum" placeholder="serial number">
139              </div>
140              <div class="form-group">
141                <label for="claim_type">Access Required</label><br>
142                <label class="radio-inline"><input type="radio" name="claim_type" value="owner" checked> Owner</label>
143                <label class="radio-inline"><input type="radio" name="claim_type" value="installer"> Installer</label>
144              </div>
145              <button type="button" id="add_claim" class="btn btn-primary" value="Add">Add System</button>
146            </form>
147            <br /><br /><br />
148            <div id="claim_failed"></div>
149          </div>
150        </div>
151      </div>
152    </div>
153  </div>
154</div>
155<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDl070Qq1sR3HnNr3LegChHPV8c7WWjZM4"></script>
156<script type="text/javascript">
157    var map = new google.maps.Map(document.getElementById('map'), {
158        zoom: 10,
159        center: {lat: -37.7621346, lng: 145.3132782 },
160        gestureHandling: 'cooperative',
161        streetViewControl: false,
162        fullscreenControl: false
163    });
164    var getData=function(installer) {
165        $.ajax({
166            url:'systems/list'+(installer ? '/installer' : '/owner'),
167            type:'get',
168            dataType: 'json',
169            cache: false,
170            success:function(data) {
171                var tableID = data.installer ? 'installerSystems' : 'ownerSystems';
172                // data=JSON.parse(data);
173                if(data.systems.length) {
174                    var content="";
175                    var time_diff;
176                    data.systems.forEach(function(d) {
177                        content+="<tr onmouseover='zoom("+d.lat+","+d.lng+")' onmouseout='zoomout()'>";
178                        content+="<td><a href='/dashboard/"+d.did+"'>"+d.name+"</a></td>";
179                        content+="<td>";
180                        var con_stat="<span class='glyphicon glyphicon-ok-sign color-green s-large' style='vertical-align:middle;'></span> ";
181                        if (d.events) con_stat="<span class='glyphicon glyphicon-exclamation-sign color-yellow s-large' style='vertical-align:middle;'></span> ";
182                        if (d.last) {
183                            time_diff = d.delta_ts;
184                            console.log("time_diff="+time_diff);
185                            if(time_diff<60) {
186                                con_stat+="<span>"+Math.round(time_diff)+" seconds ago</span>";
187                            }
188                            else if(time_diff<1200) {
189                                con_stat+="<span>"+Math.round(time_diff/60)+" minutes ago</span>";
190                            }
191                            else if(time_diff<3600) {
192                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
193                                con_stat+="<span>"+Math.round(time_diff/60)+" minutes ago</span>";
194                            }
195                            else if(time_diff<86400) {
196                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
197                                con_stat+="<span>"+Math.round(time_diff/3600)+" hours ago</span>";
198                            }
199                            else {
200                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
201                                con_stat+="<span>"+Math.round(time_diff/86400)+" days ago</span>";
202                            }
203                            content+=con_stat;
204                            content+="</td>";
205                            if ('battery_soc' in d.last) {
206                                content+="<td>"+d.last.battery_soc+"%</td>";
207                            }
208                            else {
209                                content+="<td class='hidden-xs'>—</td>";
210                            }
211                            if ('solar_wh_total' in d.last) {
212                                content+="<td class='hidden-xs'>"+d.last.solar_wh_total.toFixed()+" kWh</td>";
213                            }
214                            else {
215                                content+="<td class='hidden-xs'>—</td>";
216                            }
217                            if ('grid_in_wh_total' in d.last) {
218                                content+="<td class='hidden-xs'>"+d.last.grid_in_wh_total.toFixed()+" kWh</td>";
219                            }
220                            else {
221                                content+="<td class='hidden-xs'>—</td>";
222                            }
223                            if ('load_wh_total' in d.last) {
224                                content+="<td class='hidden-xs'>"+d.last.load_wh_total.toFixed()+" kWh</td>";
225                            }
226                            else {
227                                content+="<td class='hidden-xs'>—</td>";
228                            }
229                        }
230                        else {
231                            content += "<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span>";
232                            content += "<span>No Measurements Recorded</span></td>";
233                            content += "<td>—</td><td class='hidden-xs'>—</td><td class='hidden-xs'>—</td><td class='hidden-xs'>—</td>";
234                        }
235                        content+="</tr>";
236                        var marker=new google.maps.Marker({position: {lat: d.lat, lng: d.lng}, map: map, title:d.name});
237                    });
238                    $('table#'+tableID+' tbody').html(content);
239                    if (data.installer) $('div#otherSystems.hidden').removeClass('hidden');
240                }
241                else if (!data.installer) {
242                    $('table#'+tableID+' tbody').html("<tr><td colspan='7'>You don't have any SP Pro Systems</td></tr>");
243                }
244            }
245        });
246    }
247    var addSystem=function() {
248        var serial = $('#claim_serial').val();
249        var code = $('#claim_code').val();
250        var access = $('input[name=claim_type]:checked').val();
251        console.log('Attempting to claim with serial='+serial+', code='+code+', access='+access);
252        $.ajax({
253            url:'systems/claim',
254            type:'post',
255            data: { code: code, serial: serial, access: access },
256            dataType: 'json',
257            cache: false
258        })
259          .done(function(data) {
260                  var is_installer = (data.access == 'installer') ? true : false;
261                  $('.overlay').hide();
262                  $('div#claim_failed').html('');
263                  $('form#claim_form input').val('');
264                  getData(is_installer);
265                })
266          .fail(function(data) {
267                  if (data.responseJSON.reason.match(/No matching inverter/i)) {
268                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Could not find a matching inverter</h3>'
269                                                +'<p class="text-danger">Please check the following to fix this error:</p>'
270                                                +'<ul class="text-danger" style="padding-left:20px;">'
271                                                +'<li>Check that the Select.Live Device is powered on with text visible on the screen'
272                                                +'<li>Check that the Select.Live Device screen shows "Cloud: OK" and an IP address'
273                                                +'<li>If the Select.Live Device screen shows "Cloud: ERROR" or "Cloud: NO LAN":'
274                                                +'<ul style="padding-left:50px;">'
275                                                +'<li>for WiFi connection, check your WiFi router is operating correctly, and reset it if necessary'
276                                                +'<li>for WiFi connection, check that there is a good WiFi signal at your Select.Live device<br>'
277                                                +      '(use your mobile phone or tablet to confirm that the WiFi signal is present)'
278                                                +'<li>for Ethernet connection, check that the cable is plugged in firmly at both ends;'
279                                                +     ' also check using another device, e.g. a laptop computer, that the cable is working.'
280                                                +'</ul></ul>'
281                                                +'<p class="text-danger">If you have checked all the above and still get this error when you '
282                                                +'attempt to add the system, you will need to reset your Select.Live device and start the '
283                                                +'setup process again.  To reset your Select.Live Device, press and hold the black reset button '
284                                                +'for 10 seconds.</p>');
285                  }
286                  else if (data.responseJSON.reason.match(/Access Denied/i)) {
287                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Access denied by owner</h3>'
288                                                +'<p class="text-danger">The owner of this SP PRO has not given permission for you to have access.</p>'
289                                                +'<p class="text-danger">Please check you entered the correct <b>Device ID</b> and <b>Serial number</b>.'
290                                                +' If you think they are correct, you will need to ask the owner of this SP PRO to grant access.</p>');
291                  }
292                  else if (data.responseJSON.reason.match(/No Owner/i)) {
293                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Access Denied</h3>'
294                                                +'<p class="text-danger">Installer access to this SP PRO is not allowed.</p>');
295                  }
296                  else {
297                      $('.overlay').hide();
298                      alert(data.responseJSON.reason);
299                  }
300                });
301    };
302    $('a.add_system').on('click',function(){
303        $('.overlay').show();
304    });
305    $('a.overlay_close').on('click',function(){
306        $('.overlay').hide();
307    });
308    $('#add_claim').on('click',addSystem);
309    $('button.side-toggle').on('click',function(){
310        if($(this).hasClass("openned")) {
311            $(this).removeClass("openned");
312            $(".side-menu").removeClass("in");
313        }
314        else {
315            $(this).addClass("openned");
316            $(".side-menu").addClass("in");
317        }
318    });
319    var zoom=function(x,y) {
320        map.panTo({lat:x,lng: y});
321        map.setZoom(18);
322    }
323    var zoomout=function() {
324        map.setZoom(10);
325    }
326    $(window).ready(function() {
327        getData(false);
328    });
329    $(window).resize(function(){
330    });
331</script> 
332
333    </body>
334</html>

Here is my script so far

1if ('battery_soc' in d.last) {
2  content+="<td>"+d.last.battery_soc+"%</td>";
3}
4else {
5   content+="<td class='hidden-xs'>—</td>";
6}<!DOCTYPE html>
7<html>
8    <head>
9        <meta charset="utf-8">
10        <meta http-equiv="X-UA-Compatible" content="IE=9;IE=10;IE=Edge,chrome=1" />
11        <meta name="viewport" content="width=device-width, initial-scale=1" />
12        <meta name="Description" content="Select.Live is web based SCADA for SP Pro inverters and its system" />
13        <meta name="Author" content="Selctronic Australia Pty Ltd" />
14        <title>Select.Live Portal | Selectronic Australia</title>
15        <link href="https://fonts.googleapis.com/css?family=Titillium+Web" rel="stylesheet">
16        <link href="/css/bootstrap.min.css" rel="stylesheet" />
17        <link href="/css/zebra_datepicker.min.css" rel="stylesheet" />
18        <link href="/css/ad-style.css" rel="stylesheet" />
19        <script src="/js/jquery.min.js"></script>
20        <script src="/js/bootstrap.min.js"></script>
21        <script src="/js/zebra_datepicker.min.js"></script>
22        <script src="/js/user_geolocation.js"></script>
23        <script type="text/javascript">
24         var geocodeKey = "";
25        </script>
26    </head>
27
28    <body>
29    <div class="ad-header">
30        <button type="button" class="side-toggle left hidden-sm hidden-md hidden-lg" data-toggle="open">
31            <span class="bar"></span> <span class="bar"></span> <span class="bar"></span>
32        </button>
33        <div class="header-logo left"></div>
34        <div class="clear"></div>
35    </div>
36
37    
38<div class="section">
39
40  <div align="center" class="side-menu">
41    <ul>
42      <li><a href="/systems"><span class="glyphicon glyphicon-list"></span><span class="hideit">Systems</span></a></li>
43      <li><a href="/myprofile"><span class="glyphicon glyphicon-user"></span><span class="hideit">My Profile</span></a></li>
44      <li><a href="/logout"><span class="glyphicon glyphicon-log-out"></span><span class="hideit">Logout</span></a></li>
45    </ul>
46  </div>
47  <script type="text/javascript">
48    $(".side-menu li:nth-child(1)").addClass("active");
49  </script>
50
51
52  <div class="main-content container-fluid">
53    <div class="row">
54      <div id="map" style="height: 300px;"></div>
55    </div>
56
57    <!-- My Systems -->
58    <div class="row">
59      <div class="col col-md-12 main-content-padding">
60        <div class="main-content-inner">
61          <div class="main-content-header">
62            <h3>My Systems</h3>
63          </div>
64          <div class="main-content-body">
65            <table id="ownerSystems" class="table table-hover table-responsive table-striped">
66              <thead>
67                <tr>
68                  <th>System Name</th>
69                  <th>Status</th>
70                  <th>SoC</th>
71                  <th class="hidden-xs">Production</th>
72                  <th class="hidden-xs">Purchased</th>
73                  <th class="hidden-xs">Consumption</th>
74                </tr>
75              </thead>
76              <tbody>
77              </tbody>
78            </table>
79            <div align="right"> <a href="#" class="add_system btn btn-primary btn-lg"><span class="glyphicon glyphicon-plus"></span> Add a System</a> </div>
80          </div>
81        </div>
82      </div>
83    </div>
84
85    <!-- Other systems (have installer access to these) 0 -->
86    <div id="otherSystems" class="row hidden" >
87<div class="col col-md-12 main-content-padding">
88        <div class="main-content-inner">
89          <div class="main-content-header">
90            <h3>Other Systems</h3>
91          </div>
92          <div class="main-content-body">
93            <table id="installerSystems" class="table table-hover table-responsive table-striped">
94              <thead>
95                <tr>
96                  <th>System Name</th>
97                  <th>Status</th>
98                  <th>SoC</th>
99                  <th class="hidden-xs">Production</th>
100                  <th class="hidden-xs">Purchased</th>
101                  <th class="hidden-xs">Consumption</th>
102                </tr>
103              </thead>
104              <tbody>
105              </tbody>
106            </table>
107          </div>
108        </div>
109      </div>
110    </div>
111
112    <div class="clear"></div>
113  </div>
114</div>
115<div class="overlay">
116  <div class="container">
117    <div class="row">
118      <div class="col-sm-12">
119        <div class="overlay_content" style="overflow-y: auto;">
120          <div class="overlay_header">
121            <div class="right"> <a href="#" class="overlay_close"><span class="glyphicon glyphicon-remove"></span></a> </div>
122            <div class="clearfix"></div>
123          </div>
124          <div class="overlay_body">
125            <h3>Add a new System to your profile</h3>
126            <p>Connect your Select.Live Device to your SP PRO and set it up so that it is connected to the Internet.</p>
127            <p>Please find the Device ID and Serial number on the LCD screen of your Select.Live Device as shown in the example,
128            and copy those details into the form below.
129            </p>
130            <img src="images/LCD_claim_Selectronic.png">
131            <form id="claim_form" style="clear:both;">
132              <div class="form-group">
133                <label for="claim_code">Device ID</label>
134                <input type="text" id="claim_code" class="form-control" name="devhash" placeholder="id">
135              </div>
136              <div class="form-group">
137                <label for="claim_serial">Serial</label>
138                <input type="text" id="claim_serial" class="form-control" name="serialnum" placeholder="serial number">
139              </div>
140              <div class="form-group">
141                <label for="claim_type">Access Required</label><br>
142                <label class="radio-inline"><input type="radio" name="claim_type" value="owner" checked> Owner</label>
143                <label class="radio-inline"><input type="radio" name="claim_type" value="installer"> Installer</label>
144              </div>
145              <button type="button" id="add_claim" class="btn btn-primary" value="Add">Add System</button>
146            </form>
147            <br /><br /><br />
148            <div id="claim_failed"></div>
149          </div>
150        </div>
151      </div>
152    </div>
153  </div>
154</div>
155<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDl070Qq1sR3HnNr3LegChHPV8c7WWjZM4"></script>
156<script type="text/javascript">
157    var map = new google.maps.Map(document.getElementById('map'), {
158        zoom: 10,
159        center: {lat: -37.7621346, lng: 145.3132782 },
160        gestureHandling: 'cooperative',
161        streetViewControl: false,
162        fullscreenControl: false
163    });
164    var getData=function(installer) {
165        $.ajax({
166            url:'systems/list'+(installer ? '/installer' : '/owner'),
167            type:'get',
168            dataType: 'json',
169            cache: false,
170            success:function(data) {
171                var tableID = data.installer ? 'installerSystems' : 'ownerSystems';
172                // data=JSON.parse(data);
173                if(data.systems.length) {
174                    var content="";
175                    var time_diff;
176                    data.systems.forEach(function(d) {
177                        content+="<tr onmouseover='zoom("+d.lat+","+d.lng+")' onmouseout='zoomout()'>";
178                        content+="<td><a href='/dashboard/"+d.did+"'>"+d.name+"</a></td>";
179                        content+="<td>";
180                        var con_stat="<span class='glyphicon glyphicon-ok-sign color-green s-large' style='vertical-align:middle;'></span> ";
181                        if (d.events) con_stat="<span class='glyphicon glyphicon-exclamation-sign color-yellow s-large' style='vertical-align:middle;'></span> ";
182                        if (d.last) {
183                            time_diff = d.delta_ts;
184                            console.log("time_diff="+time_diff);
185                            if(time_diff<60) {
186                                con_stat+="<span>"+Math.round(time_diff)+" seconds ago</span>";
187                            }
188                            else if(time_diff<1200) {
189                                con_stat+="<span>"+Math.round(time_diff/60)+" minutes ago</span>";
190                            }
191                            else if(time_diff<3600) {
192                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
193                                con_stat+="<span>"+Math.round(time_diff/60)+" minutes ago</span>";
194                            }
195                            else if(time_diff<86400) {
196                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
197                                con_stat+="<span>"+Math.round(time_diff/3600)+" hours ago</span>";
198                            }
199                            else {
200                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
201                                con_stat+="<span>"+Math.round(time_diff/86400)+" days ago</span>";
202                            }
203                            content+=con_stat;
204                            content+="</td>";
205                            if ('battery_soc' in d.last) {
206                                content+="<td>"+d.last.battery_soc+"%</td>";
207                            }
208                            else {
209                                content+="<td class='hidden-xs'>—</td>";
210                            }
211                            if ('solar_wh_total' in d.last) {
212                                content+="<td class='hidden-xs'>"+d.last.solar_wh_total.toFixed()+" kWh</td>";
213                            }
214                            else {
215                                content+="<td class='hidden-xs'>—</td>";
216                            }
217                            if ('grid_in_wh_total' in d.last) {
218                                content+="<td class='hidden-xs'>"+d.last.grid_in_wh_total.toFixed()+" kWh</td>";
219                            }
220                            else {
221                                content+="<td class='hidden-xs'>—</td>";
222                            }
223                            if ('load_wh_total' in d.last) {
224                                content+="<td class='hidden-xs'>"+d.last.load_wh_total.toFixed()+" kWh</td>";
225                            }
226                            else {
227                                content+="<td class='hidden-xs'>—</td>";
228                            }
229                        }
230                        else {
231                            content += "<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span>";
232                            content += "<span>No Measurements Recorded</span></td>";
233                            content += "<td>—</td><td class='hidden-xs'>—</td><td class='hidden-xs'>—</td><td class='hidden-xs'>—</td>";
234                        }
235                        content+="</tr>";
236                        var marker=new google.maps.Marker({position: {lat: d.lat, lng: d.lng}, map: map, title:d.name});
237                    });
238                    $('table#'+tableID+' tbody').html(content);
239                    if (data.installer) $('div#otherSystems.hidden').removeClass('hidden');
240                }
241                else if (!data.installer) {
242                    $('table#'+tableID+' tbody').html("<tr><td colspan='7'>You don't have any SP Pro Systems</td></tr>");
243                }
244            }
245        });
246    }
247    var addSystem=function() {
248        var serial = $('#claim_serial').val();
249        var code = $('#claim_code').val();
250        var access = $('input[name=claim_type]:checked').val();
251        console.log('Attempting to claim with serial='+serial+', code='+code+', access='+access);
252        $.ajax({
253            url:'systems/claim',
254            type:'post',
255            data: { code: code, serial: serial, access: access },
256            dataType: 'json',
257            cache: false
258        })
259          .done(function(data) {
260                  var is_installer = (data.access == 'installer') ? true : false;
261                  $('.overlay').hide();
262                  $('div#claim_failed').html('');
263                  $('form#claim_form input').val('');
264                  getData(is_installer);
265                })
266          .fail(function(data) {
267                  if (data.responseJSON.reason.match(/No matching inverter/i)) {
268                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Could not find a matching inverter</h3>'
269                                                +'<p class="text-danger">Please check the following to fix this error:</p>'
270                                                +'<ul class="text-danger" style="padding-left:20px;">'
271                                                +'<li>Check that the Select.Live Device is powered on with text visible on the screen'
272                                                +'<li>Check that the Select.Live Device screen shows "Cloud: OK" and an IP address'
273                                                +'<li>If the Select.Live Device screen shows "Cloud: ERROR" or "Cloud: NO LAN":'
274                                                +'<ul style="padding-left:50px;">'
275                                                +'<li>for WiFi connection, check your WiFi router is operating correctly, and reset it if necessary'
276                                                +'<li>for WiFi connection, check that there is a good WiFi signal at your Select.Live device<br>'
277                                                +      '(use your mobile phone or tablet to confirm that the WiFi signal is present)'
278                                                +'<li>for Ethernet connection, check that the cable is plugged in firmly at both ends;'
279                                                +     ' also check using another device, e.g. a laptop computer, that the cable is working.'
280                                                +'</ul></ul>'
281                                                +'<p class="text-danger">If you have checked all the above and still get this error when you '
282                                                +'attempt to add the system, you will need to reset your Select.Live device and start the '
283                                                +'setup process again.  To reset your Select.Live Device, press and hold the black reset button '
284                                                +'for 10 seconds.</p>');
285                  }
286                  else if (data.responseJSON.reason.match(/Access Denied/i)) {
287                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Access denied by owner</h3>'
288                                                +'<p class="text-danger">The owner of this SP PRO has not given permission for you to have access.</p>'
289                                                +'<p class="text-danger">Please check you entered the correct <b>Device ID</b> and <b>Serial number</b>.'
290                                                +' If you think they are correct, you will need to ask the owner of this SP PRO to grant access.</p>');
291                  }
292                  else if (data.responseJSON.reason.match(/No Owner/i)) {
293                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Access Denied</h3>'
294                                                +'<p class="text-danger">Installer access to this SP PRO is not allowed.</p>');
295                  }
296                  else {
297                      $('.overlay').hide();
298                      alert(data.responseJSON.reason);
299                  }
300                });
301    };
302    $('a.add_system').on('click',function(){
303        $('.overlay').show();
304    });
305    $('a.overlay_close').on('click',function(){
306        $('.overlay').hide();
307    });
308    $('#add_claim').on('click',addSystem);
309    $('button.side-toggle').on('click',function(){
310        if($(this).hasClass("openned")) {
311            $(this).removeClass("openned");
312            $(".side-menu").removeClass("in");
313        }
314        else {
315            $(this).addClass("openned");
316            $(".side-menu").addClass("in");
317        }
318    });
319    var zoom=function(x,y) {
320        map.panTo({lat:x,lng: y});
321        map.setZoom(18);
322    }
323    var zoomout=function() {
324        map.setZoom(10);
325    }
326    $(window).ready(function() {
327        getData(false);
328    });
329    $(window).resize(function(){
330    });
331</script> 
332
333    </body>
334</html>const scrapePersons = async () => {
335    // import launchChrome and newPage from the browser.js file in the same directory
336    const { launchChrome } = require("./browser");
337
338    // Flow 1 => Launching chrome and opening a new tab/page
339    const [newPage, exitChrome] = await launchChrome();
340    const [page] = await newPage();
341
342    const emailSelector="input[name=email]";
343    const pwdSelector="input[name=pwd]";
344    const btnSelector=".btn";
345
346    // exit the function if the tab is not properly opened
347    if (!page) return;
348
349    // Flow 2 => Visiting a website's home page
350    const url = "https://select.live/";
351    console.log("Opening " + url);
352    try {
353        await page.goto(url, {
354        waitUntil: "networkidle0", // wait till all network requests has been processed
355        });
356    } catch(e) {
357        console.error("Unable to visit " + url, e);
358        await exitChrome(); // close chrome on error
359        return; // exiting the function
360    }
361
362    //Perform the Login
363    await page.waitForSelector(emailSelector);
364    console.log('40 Found name="email" on page');
365
366    await page.waitForSelector(pwdSelector);
367    console.log('50 Found name="pwd" on page');
368
369    await page.waitForSelector(btnSelector);
370    console.log('55 Found the button with class namne btn');
371
372    await page.type(emailSelector, 'Username Goes Here');
373    await page.type(pwdSelector, 'Password Goes Here');
374    console.log('60 Entered email and password');
375
376    //Click the Login Butotn
377    try{
378        await page.click(btnSelector);
379        console.log('70 Clicked the Login Button');
380    }
381    catch(e){
382       console.error('Unable to click the login button' + btnSelector + ' ', e)
383    }
384
385    // Find the Power Percentage Value
386    
387
388    await exitChrome(); // close chrome
389    console.log('900 Exited Chrome')
390};
391
392module.exports = scrapePersons;

ANSWER

Answered 2022-Apr-17 at 10:16

try waiting for table cell to be rendered with page.waitForSelector:

1if ('battery_soc' in d.last) {
2  content+="<td>"+d.last.battery_soc+"%</td>";
3}
4else {
5   content+="<td class='hidden-xs'>—</td>";
6}<!DOCTYPE html>
7<html>
8    <head>
9        <meta charset="utf-8">
10        <meta http-equiv="X-UA-Compatible" content="IE=9;IE=10;IE=Edge,chrome=1" />
11        <meta name="viewport" content="width=device-width, initial-scale=1" />
12        <meta name="Description" content="Select.Live is web based SCADA for SP Pro inverters and its system" />
13        <meta name="Author" content="Selctronic Australia Pty Ltd" />
14        <title>Select.Live Portal | Selectronic Australia</title>
15        <link href="https://fonts.googleapis.com/css?family=Titillium+Web" rel="stylesheet">
16        <link href="/css/bootstrap.min.css" rel="stylesheet" />
17        <link href="/css/zebra_datepicker.min.css" rel="stylesheet" />
18        <link href="/css/ad-style.css" rel="stylesheet" />
19        <script src="/js/jquery.min.js"></script>
20        <script src="/js/bootstrap.min.js"></script>
21        <script src="/js/zebra_datepicker.min.js"></script>
22        <script src="/js/user_geolocation.js"></script>
23        <script type="text/javascript">
24         var geocodeKey = "";
25        </script>
26    </head>
27
28    <body>
29    <div class="ad-header">
30        <button type="button" class="side-toggle left hidden-sm hidden-md hidden-lg" data-toggle="open">
31            <span class="bar"></span> <span class="bar"></span> <span class="bar"></span>
32        </button>
33        <div class="header-logo left"></div>
34        <div class="clear"></div>
35    </div>
36
37    
38<div class="section">
39
40  <div align="center" class="side-menu">
41    <ul>
42      <li><a href="/systems"><span class="glyphicon glyphicon-list"></span><span class="hideit">Systems</span></a></li>
43      <li><a href="/myprofile"><span class="glyphicon glyphicon-user"></span><span class="hideit">My Profile</span></a></li>
44      <li><a href="/logout"><span class="glyphicon glyphicon-log-out"></span><span class="hideit">Logout</span></a></li>
45    </ul>
46  </div>
47  <script type="text/javascript">
48    $(".side-menu li:nth-child(1)").addClass("active");
49  </script>
50
51
52  <div class="main-content container-fluid">
53    <div class="row">
54      <div id="map" style="height: 300px;"></div>
55    </div>
56
57    <!-- My Systems -->
58    <div class="row">
59      <div class="col col-md-12 main-content-padding">
60        <div class="main-content-inner">
61          <div class="main-content-header">
62            <h3>My Systems</h3>
63          </div>
64          <div class="main-content-body">
65            <table id="ownerSystems" class="table table-hover table-responsive table-striped">
66              <thead>
67                <tr>
68                  <th>System Name</th>
69                  <th>Status</th>
70                  <th>SoC</th>
71                  <th class="hidden-xs">Production</th>
72                  <th class="hidden-xs">Purchased</th>
73                  <th class="hidden-xs">Consumption</th>
74                </tr>
75              </thead>
76              <tbody>
77              </tbody>
78            </table>
79            <div align="right"> <a href="#" class="add_system btn btn-primary btn-lg"><span class="glyphicon glyphicon-plus"></span> Add a System</a> </div>
80          </div>
81        </div>
82      </div>
83    </div>
84
85    <!-- Other systems (have installer access to these) 0 -->
86    <div id="otherSystems" class="row hidden" >
87<div class="col col-md-12 main-content-padding">
88        <div class="main-content-inner">
89          <div class="main-content-header">
90            <h3>Other Systems</h3>
91          </div>
92          <div class="main-content-body">
93            <table id="installerSystems" class="table table-hover table-responsive table-striped">
94              <thead>
95                <tr>
96                  <th>System Name</th>
97                  <th>Status</th>
98                  <th>SoC</th>
99                  <th class="hidden-xs">Production</th>
100                  <th class="hidden-xs">Purchased</th>
101                  <th class="hidden-xs">Consumption</th>
102                </tr>
103              </thead>
104              <tbody>
105              </tbody>
106            </table>
107          </div>
108        </div>
109      </div>
110    </div>
111
112    <div class="clear"></div>
113  </div>
114</div>
115<div class="overlay">
116  <div class="container">
117    <div class="row">
118      <div class="col-sm-12">
119        <div class="overlay_content" style="overflow-y: auto;">
120          <div class="overlay_header">
121            <div class="right"> <a href="#" class="overlay_close"><span class="glyphicon glyphicon-remove"></span></a> </div>
122            <div class="clearfix"></div>
123          </div>
124          <div class="overlay_body">
125            <h3>Add a new System to your profile</h3>
126            <p>Connect your Select.Live Device to your SP PRO and set it up so that it is connected to the Internet.</p>
127            <p>Please find the Device ID and Serial number on the LCD screen of your Select.Live Device as shown in the example,
128            and copy those details into the form below.
129            </p>
130            <img src="images/LCD_claim_Selectronic.png">
131            <form id="claim_form" style="clear:both;">
132              <div class="form-group">
133                <label for="claim_code">Device ID</label>
134                <input type="text" id="claim_code" class="form-control" name="devhash" placeholder="id">
135              </div>
136              <div class="form-group">
137                <label for="claim_serial">Serial</label>
138                <input type="text" id="claim_serial" class="form-control" name="serialnum" placeholder="serial number">
139              </div>
140              <div class="form-group">
141                <label for="claim_type">Access Required</label><br>
142                <label class="radio-inline"><input type="radio" name="claim_type" value="owner" checked> Owner</label>
143                <label class="radio-inline"><input type="radio" name="claim_type" value="installer"> Installer</label>
144              </div>
145              <button type="button" id="add_claim" class="btn btn-primary" value="Add">Add System</button>
146            </form>
147            <br /><br /><br />
148            <div id="claim_failed"></div>
149          </div>
150        </div>
151      </div>
152    </div>
153  </div>
154</div>
155<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDl070Qq1sR3HnNr3LegChHPV8c7WWjZM4"></script>
156<script type="text/javascript">
157    var map = new google.maps.Map(document.getElementById('map'), {
158        zoom: 10,
159        center: {lat: -37.7621346, lng: 145.3132782 },
160        gestureHandling: 'cooperative',
161        streetViewControl: false,
162        fullscreenControl: false
163    });
164    var getData=function(installer) {
165        $.ajax({
166            url:'systems/list'+(installer ? '/installer' : '/owner'),
167            type:'get',
168            dataType: 'json',
169            cache: false,
170            success:function(data) {
171                var tableID = data.installer ? 'installerSystems' : 'ownerSystems';
172                // data=JSON.parse(data);
173                if(data.systems.length) {
174                    var content="";
175                    var time_diff;
176                    data.systems.forEach(function(d) {
177                        content+="<tr onmouseover='zoom("+d.lat+","+d.lng+")' onmouseout='zoomout()'>";
178                        content+="<td><a href='/dashboard/"+d.did+"'>"+d.name+"</a></td>";
179                        content+="<td>";
180                        var con_stat="<span class='glyphicon glyphicon-ok-sign color-green s-large' style='vertical-align:middle;'></span> ";
181                        if (d.events) con_stat="<span class='glyphicon glyphicon-exclamation-sign color-yellow s-large' style='vertical-align:middle;'></span> ";
182                        if (d.last) {
183                            time_diff = d.delta_ts;
184                            console.log("time_diff="+time_diff);
185                            if(time_diff<60) {
186                                con_stat+="<span>"+Math.round(time_diff)+" seconds ago</span>";
187                            }
188                            else if(time_diff<1200) {
189                                con_stat+="<span>"+Math.round(time_diff/60)+" minutes ago</span>";
190                            }
191                            else if(time_diff<3600) {
192                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
193                                con_stat+="<span>"+Math.round(time_diff/60)+" minutes ago</span>";
194                            }
195                            else if(time_diff<86400) {
196                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
197                                con_stat+="<span>"+Math.round(time_diff/3600)+" hours ago</span>";
198                            }
199                            else {
200                                con_stat="<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span> ";
201                                con_stat+="<span>"+Math.round(time_diff/86400)+" days ago</span>";
202                            }
203                            content+=con_stat;
204                            content+="</td>";
205                            if ('battery_soc' in d.last) {
206                                content+="<td>"+d.last.battery_soc+"%</td>";
207                            }
208                            else {
209                                content+="<td class='hidden-xs'>—</td>";
210                            }
211                            if ('solar_wh_total' in d.last) {
212                                content+="<td class='hidden-xs'>"+d.last.solar_wh_total.toFixed()+" kWh</td>";
213                            }
214                            else {
215                                content+="<td class='hidden-xs'>—</td>";
216                            }
217                            if ('grid_in_wh_total' in d.last) {
218                                content+="<td class='hidden-xs'>"+d.last.grid_in_wh_total.toFixed()+" kWh</td>";
219                            }
220                            else {
221                                content+="<td class='hidden-xs'>—</td>";
222                            }
223                            if ('load_wh_total' in d.last) {
224                                content+="<td class='hidden-xs'>"+d.last.load_wh_total.toFixed()+" kWh</td>";
225                            }
226                            else {
227                                content+="<td class='hidden-xs'>—</td>";
228                            }
229                        }
230                        else {
231                            content += "<span class='glyphicon glyphicon-remove-sign color-red s-large' style='vertical-align:middle;'></span>";
232                            content += "<span>No Measurements Recorded</span></td>";
233                            content += "<td>—</td><td class='hidden-xs'>—</td><td class='hidden-xs'>—</td><td class='hidden-xs'>—</td>";
234                        }
235                        content+="</tr>";
236                        var marker=new google.maps.Marker({position: {lat: d.lat, lng: d.lng}, map: map, title:d.name});
237                    });
238                    $('table#'+tableID+' tbody').html(content);
239                    if (data.installer) $('div#otherSystems.hidden').removeClass('hidden');
240                }
241                else if (!data.installer) {
242                    $('table#'+tableID+' tbody').html("<tr><td colspan='7'>You don't have any SP Pro Systems</td></tr>");
243                }
244            }
245        });
246    }
247    var addSystem=function() {
248        var serial = $('#claim_serial').val();
249        var code = $('#claim_code').val();
250        var access = $('input[name=claim_type]:checked').val();
251        console.log('Attempting to claim with serial='+serial+', code='+code+', access='+access);
252        $.ajax({
253            url:'systems/claim',
254            type:'post',
255            data: { code: code, serial: serial, access: access },
256            dataType: 'json',
257            cache: false
258        })
259          .done(function(data) {
260                  var is_installer = (data.access == 'installer') ? true : false;
261                  $('.overlay').hide();
262                  $('div#claim_failed').html('');
263                  $('form#claim_form input').val('');
264                  getData(is_installer);
265                })
266          .fail(function(data) {
267                  if (data.responseJSON.reason.match(/No matching inverter/i)) {
268                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Could not find a matching inverter</h3>'
269                                                +'<p class="text-danger">Please check the following to fix this error:</p>'
270                                                +'<ul class="text-danger" style="padding-left:20px;">'
271                                                +'<li>Check that the Select.Live Device is powered on with text visible on the screen'
272                                                +'<li>Check that the Select.Live Device screen shows "Cloud: OK" and an IP address'
273                                                +'<li>If the Select.Live Device screen shows "Cloud: ERROR" or "Cloud: NO LAN":'
274                                                +'<ul style="padding-left:50px;">'
275                                                +'<li>for WiFi connection, check your WiFi router is operating correctly, and reset it if necessary'
276                                                +'<li>for WiFi connection, check that there is a good WiFi signal at your Select.Live device<br>'
277                                                +      '(use your mobile phone or tablet to confirm that the WiFi signal is present)'
278                                                +'<li>for Ethernet connection, check that the cable is plugged in firmly at both ends;'
279                                                +     ' also check using another device, e.g. a laptop computer, that the cable is working.'
280                                                +'</ul></ul>'
281                                                +'<p class="text-danger">If you have checked all the above and still get this error when you '
282                                                +'attempt to add the system, you will need to reset your Select.Live device and start the '
283                                                +'setup process again.  To reset your Select.Live Device, press and hold the black reset button '
284                                                +'for 10 seconds.</p>');
285                  }
286                  else if (data.responseJSON.reason.match(/Access Denied/i)) {
287                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Access denied by owner</h3>'
288                                                +'<p class="text-danger">The owner of this SP PRO has not given permission for you to have access.</p>'
289                                                +'<p class="text-danger">Please check you entered the correct <b>Device ID</b> and <b>Serial number</b>.'
290                                                +' If you think they are correct, you will need to ask the owner of this SP PRO to grant access.</p>');
291                  }
292                  else if (data.responseJSON.reason.match(/No Owner/i)) {
293                      $('div#claim_failed').html('<p> </p><h3 class="text-danger">Access Denied</h3>'
294                                                +'<p class="text-danger">Installer access to this SP PRO is not allowed.</p>');
295                  }
296                  else {
297                      $('.overlay').hide();
298                      alert(data.responseJSON.reason);
299                  }
300                });
301    };
302    $('a.add_system').on('click',function(){
303        $('.overlay').show();
304    });
305    $('a.overlay_close').on('click',function(){
306        $('.overlay').hide();
307    });
308    $('#add_claim').on('click',addSystem);
309    $('button.side-toggle').on('click',function(){
310        if($(this).hasClass("openned")) {
311            $(this).removeClass("openned");
312            $(".side-menu").removeClass("in");
313        }
314        else {
315            $(this).addClass("openned");
316            $(".side-menu").addClass("in");
317        }
318    });
319    var zoom=function(x,y) {
320        map.panTo({lat:x,lng: y});
321        map.setZoom(18);
322    }
323    var zoomout=function() {
324        map.setZoom(10);
325    }
326    $(window).ready(function() {
327        getData(false);
328    });
329    $(window).resize(function(){
330    });
331</script> 
332
333    </body>
334</html>const scrapePersons = async () => {
335    // import launchChrome and newPage from the browser.js file in the same directory
336    const { launchChrome } = require("./browser");
337
338    // Flow 1 => Launching chrome and opening a new tab/page
339    const [newPage, exitChrome] = await launchChrome();
340    const [page] = await newPage();
341
342    const emailSelector="input[name=email]";
343    const pwdSelector="input[name=pwd]";
344    const btnSelector=".btn";
345
346    // exit the function if the tab is not properly opened
347    if (!page) return;
348
349    // Flow 2 => Visiting a website's home page
350    const url = "https://select.live/";
351    console.log("Opening " + url);
352    try {
353        await page.goto(url, {
354        waitUntil: "networkidle0", // wait till all network requests has been processed
355        });
356    } catch(e) {
357        console.error("Unable to visit " + url, e);
358        await exitChrome(); // close chrome on error
359        return; // exiting the function
360    }
361
362    //Perform the Login
363    await page.waitForSelector(emailSelector);
364    console.log('40 Found name="email" on page');
365
366    await page.waitForSelector(pwdSelector);
367    console.log('50 Found name="pwd" on page');
368
369    await page.waitForSelector(btnSelector);
370    console.log('55 Found the button with class namne btn');
371
372    await page.type(emailSelector, 'Username Goes Here');
373    await page.type(pwdSelector, 'Password Goes Here');
374    console.log('60 Entered email and password');
375
376    //Click the Login Butotn
377    try{
378        await page.click(btnSelector);
379        console.log('70 Clicked the Login Button');
380    }
381    catch(e){
382       console.error('Unable to click the login button' + btnSelector + ' ', e)
383    }
384
385    // Find the Power Percentage Value
386    
387
388    await exitChrome(); // close chrome
389    console.log('900 Exited Chrome')
390};
391
392module.exports = scrapePersons;// systems table row
393const socSelector = '#ownerSystems tbody tr';
394
395// wait for it to render
396const socCell = await page.waitForSelector(socSelector, {
397    visible: true
398});
399
400// extract value from third cell for each row
401const socVal = await page.evaluate(socSelector => Array.from(document.querySelectorAll(`${socSelector} td:nth-child(3)`)).map(el => el.textContent), socSelector);
402
403console.log(socVal);
404

Source https://stackoverflow.com/questions/71900485

QUESTION

Android Studio BumbleBee pair wifi not working

Asked 2022-Apr-03 at 10:29

I am trying to connect my Android 11 device with android studio over adb wifi but it is not working.

I updated to latest stable bumblebee and updated my SDK I tried turning off firewall on my pc but it is same result.

When I use QR code method my android phone just shows "pairing device" and nothing happens If I try the code method, android studio just shows "searching for devices" but nothing happens

and, yes, I enabled wireless debugging on my phone and I am connected to the same wifi network.

I don't know if the problem is with my computer or phone. I do not have any other Android11+ phone to try with

ANSWER

Answered 2022-Jan-30 at 21:44

I was having the same problem as you. Neither pairing by QR nor by pairing code worked.

So I tried connecting by typing adb connect [phone_ip]:[port] in the terminal and that worked flawlessly. Didn't even need to plug the phone to the computer with USB. Your phone will tell you the IP and port right above the "pair with QR code" option inside the Wifi-debugging setting. Just connect to that address.

Source https://stackoverflow.com/questions/70905560

QUESTION

Android Studio Bumblebee Wifi pairing Issue

Asked 2022-Mar-29 at 15:31

I have used Android Studio Bumblebee's latest function (Wifi pairing) for 2 - 3 days before it stopped working.
I am now receiving the error "This system does not meet the requirements to support Wi-Fi pairing. Please update to the latest version of "platform-tools" using the SDK manager"

I have updated everything to the latest version.

Screenshot of the error message

ANSWER

Answered 2022-Feb-02 at 03:53

My guess is that you have an old version of platform-tools/adb installed somewhere (you can verify this by running which adb in your command prompt).

Find the right platform-tools

You can find the pathway to the platform-tools/adb you want to use in Android Studios under Settings -> Appearance & Behavior -> System Settings -> Android SDK. enter image description here

Inside of this folder should be another folder called "platform-tools". enter image description here

Update your PATH You'll want to add this folder to your PATH and remove the old one.

enter image description here

Restart Android Studio For the changes to take effect, you'll need to restart the IDE.

File -> Invalidate Caches -> Invalidate and Restart

Another Solution If the above doesn't work, you can also uninstall and reinstall platform-tools using the sdkmanager command.
1sdkmanager --uninstall "platform-tools"
2

Once platform-tools is uninstalled, you can use the SDK Manager in Android Studio to reinstall.

Source https://stackoverflow.com/questions/70944858

QUESTION

Is the Android Wifi-API really so broken on Android 10+?

Asked 2022-Mar-22 at 11:19

I'm working on a Wifi auto connect feature and I am shocked how broken that API is.

I'm using now 5 different APIs and I still don't get it in a way the user would expect it.

I have a setting to enable wifi auto connection on Android 10+ I'll try this:

  1. Check if I hold the ACCESS_WIFI_STATE permission with:
1appOpsManager.unsafeCheckOp("android:change_wifi_state", Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED
2
When I own the permission I go on with 2. if not I continue with 6.
  • When I hold the permission I'll check on Android 11+ if from a previous run my wifi suggestion was saved wifiManager.networkSuggestions.isNotEmpty() if that is true I check which Wifi I'm currently connected with see step x. On lower levels I skip this and go to step 3
  • I use the wifi suggestion API with the WifiNetworkSuggestion.Builder() and suggest the user my wifi with
  • 1appOpsManager.unsafeCheckOp("android:change_wifi_state", Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED
    2val status = wifiManager.addNetworkSuggestions(listOf(suggestion))
    3// Strage bug: On first usage the return value is always SUCCESS
    4val success = status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS
    5
  • When the user accepts my suggestion I'm fine so far. I cannot verify on Android 10 if my suggestion was accepted. On Android 11 this is possible (see step 2). However I still don't know if the device actually connected with the wifi. So I go to step 7
  • When the user rejected my suggestion I'm almost out of the game I can never ask the user again (well technically there is a well hidden feature where you can switch the permission, but no user will ever find it). On Android 10 I can just check if I'm connected with the right wifi, well at least theoretically (see step 7).
  • On Android 11+ I can fallback to the Settings.ACTION_WIFI_ADD_NETWORKS intent which can always add Wifis (with the downside that the user can share the wifi password)
  • I need to verify if the steps before worked and the user is actually connected to the desired wifi. To do so I already own the permissions ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE, ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION. However the ConnectivityManager API don't return the actual SSID, that drives me crazy.
  • If the user is not connected to the right wifi I would try to use the Settings.Panel.ACTION_WIFI action to let the user to connect to the right wifi
  • To summarize that:

    • I use the WifiNetworkSuggestion API
    • I fallback to Settings.ACTION_WIFI_ADD_NETWORKS where possible
    • I try to verify if the user is currently connected to the right wifi
    • I try to assist the user to conenct to the right wifi (or even turn wifi on) with the Settings.Panel.ACTION_WIFI action

    Is that really such a mess or is there a easier way?


    I'm currently accessing the SSID like this:

    1appOpsManager.unsafeCheckOp("android:change_wifi_state", Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED
    2val status = wifiManager.addNetworkSuggestions(listOf(suggestion))
    3// Strage bug: On first usage the return value is always SUCCESS
    4val success = status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS
    5private val currentSsid: String?
    6    get() =
    7        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    8            val wifiInfo = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)?.transportInfo as? WifiInfo
    9            wifiInfo?.ssid
    10        } else {
    11            wifiManager.connectionInfo?.ssid
    12        }
    13

    Based on Unable to get WIFI SSID using onCapabilitiesChanged in Android 12 I think that way I access the value is not supported. I get currently the value "<unknown ssid>".

    ANSWER

    Answered 2022-Mar-22 at 11:19

    Well just a half answer, but it might help anyway. Here is how I get the current SSID of the user (you need to hold the location permission):

    1appOpsManager.unsafeCheckOp(&quot;android:change_wifi_state&quot;, Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED
    2val status = wifiManager.addNetworkSuggestions(listOf(suggestion))
    3// Strage bug: On first usage the return value is always SUCCESS
    4val success = status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS
    5private val currentSsid: String?
    6    get() =
    7        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q) {
    8            val wifiInfo = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)?.transportInfo as? WifiInfo
    9            wifiInfo?.ssid
    10        } else {
    11            wifiManager.connectionInfo?.ssid
    12        }
    13fun updateSsid(networkCapabilities: NetworkCapabilities) {
    14    if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q) {
    15        currentSsid = (networkCapabilities.transportInfo as? WifiInfo)?.ssid?.trim('&quot;')
    16    }
    17}
    18
    19wifiCallback = when {
    20    Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.S -&gt; {
    21        object: ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
    22            override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
    23                updateSsid(networkCapabilities)
    24            }
    25        }
    26    }
    27    Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q -&gt; {
    28        object: ConnectivityManager.NetworkCallback() {
    29            override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
    30                updateSsid(networkCapabilities)
    31            }
    32        }
    33    }
    34    else -&gt; null
    35}
    36
    37wifiCallback?.let {
    38    fragment.lifecycle.addObserver(object: DefaultLifecycleObserver {
    39        override fun onResume(owner: LifecycleOwner) {
    40            connectivityManager.registerNetworkCallback(request, it)
    41        }
    42
    43        override fun onPause(owner: LifecycleOwner) {
    44            connectivityManager.unregisterNetworkCallback(it)
    45        }
    46    })
    47}
    48

    So basically aspects of your code need to check apis for the levels <10, 10, 11 and 12. What a mess.

    This might be quiet handy if you want the user to pick the configured wifi:

    1appOpsManager.unsafeCheckOp(&quot;android:change_wifi_state&quot;, Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED
    2val status = wifiManager.addNetworkSuggestions(listOf(suggestion))
    3// Strage bug: On first usage the return value is always SUCCESS
    4val success = status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS
    5private val currentSsid: String?
    6    get() =
    7        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q) {
    8            val wifiInfo = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)?.transportInfo as? WifiInfo
    9            wifiInfo?.ssid
    10        } else {
    11            wifiManager.connectionInfo?.ssid
    12        }
    13fun updateSsid(networkCapabilities: NetworkCapabilities) {
    14    if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q) {
    15        currentSsid = (networkCapabilities.transportInfo as? WifiInfo)?.ssid?.trim('&quot;')
    16    }
    17}
    18
    19wifiCallback = when {
    20    Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.S -&gt; {
    21        object: ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
    22            override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
    23                updateSsid(networkCapabilities)
    24            }
    25        }
    26    }
    27    Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q -&gt; {
    28        object: ConnectivityManager.NetworkCallback() {
    29            override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
    30                updateSsid(networkCapabilities)
    31            }
    32        }
    33    }
    34    else -&gt; null
    35}
    36
    37wifiCallback?.let {
    38    fragment.lifecycle.addObserver(object: DefaultLifecycleObserver {
    39        override fun onResume(owner: LifecycleOwner) {
    40            connectivityManager.registerNetworkCallback(request, it)
    41        }
    42
    43        override fun onPause(owner: LifecycleOwner) {
    44            connectivityManager.unregisterNetworkCallback(it)
    45        }
    46    })
    47}
    48fun showWifiDialog() {
    49    if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q) {
    50        try {
    51            fragment.startActivity(Intent(android.provider.Settings.Panel.ACTION_WIFI))
    52        } catch (e: Exception) {
    53            // ignored
    54        }
    55    }
    56}
    57

    Source https://stackoverflow.com/questions/71549864

    QUESTION

    Should macOS daemons be made from the &quot;Command Line Tool&quot; Xcode template?

    Asked 2022-Mar-20 at 19:40

    I have a few questions regarding daemons. Indeed, even the macos developer center has limited information resources.

    I want to develop an application daemon that runs after system boot without login.

    a) a Daemon; Is it a simple console application combined with a plist? Because there are almost no tutorials on daemon development related to Xcode. If there is a code sample reference, can you share it here?

    b) Can daemons be downloaded from the app store? Because there must be a software that I can offer to everyone through the App Store. Is the installation automatic like other app store apps? If anyone has experience and can share it, I would be very grateful.

    c) I am working on an API related to mirroring the screen to Android phone. Do you think a daemon has full access to WiFi/BLE and screen capture APIs?

    I would be very happy to hear your suggestions.

    ANSWER

    Answered 2022-Mar-20 at 19:32

    I've made a launch daemon in the past, for the purpose of making a privileged helper tool with SMBless. I can share some of my experience.

    A

    a Daemon; Is it a simple console application combined with a plist? Because there are almost no tutorials on daemon development related to xcode. If there is a code sample reference, can you share it here?

    Here are some resources that I found useful:

    1. Woody's Cocoa: implement a privileged Helper. This article covers the low-level, step by step process of making a launch daemon and launching it as a privileged helper tool. If you have no need for privileged execution, the steps would be much the same, but without the SMJobBless parts.
    2. SwiftAuthorizationSample which show cases SecureXPC (a framework for Swifty, Codable-based XPC communication) and Blessed (a framework for a Swifty, modern interface to SMJobBless and the AuthorizationServices framework). It handles a lot of the complexity from #1.
    3. Apple's Daemons and Services Programming Guide
    B

    Can daemons be downloaded from the app store? Because there must be a software that I can offer to everyone through the app store. Is the installation automatic like other app store apps? If anyone has experience and can share it, I would be very grateful.

    No. You would distribute them as part of an app, and make your app install them when required.

    I am working on an api related to mirroring the screen to android phone. Do you think a daemon has full access to WiFi/BLE and screen capture APIs?

    WiFi certainly, but I'm not sure about the screen capture APIs. One of the differences between launch agents and daemons (IIRC), is that only launch agents can connect to the window server, which I assume is necessary for the screen capture APIs.

    From Technical Note TN2083 – Daemons and Agents:

    Daemons

    A daemon is a program that runs in the background as part of the overall system (that is, it is not tied to a particular user). A daemon cannot display any GUI; more specifically, it is not allowed to connect to the window server. A web server is the perfect example of a daemon.

    ...

    Agents

    An agent is a process that runs in the background on behalf of a particular user. Agents are useful because they can do things that daemons can't, like reliably access the user's home directory or connect to the window server. A calendar monitoring program is a good example of an agent because:

    Source https://stackoverflow.com/questions/71549822

    QUESTION

    How to rebuild epoll package in electron?

    Asked 2022-Mar-18 at 11:41

    I try to rebuild an electron app but I got this error regarding the epoll installation.

    1Building module: epoll, Completed: 0gyp: name 'openssl_fips' is not defined while evaluating condition 'openssl_fips != &quot;&quot;' in binding.gyp while trying to load binding.gyp
    2✖ Rebuild Failed
    3An unhandled error occurred inside electron-rebuild
    4node-gyp failed to rebuild '/home/pi/ma-0042-cihaz-be/node_modules/epoll'.
    5For more information, rerun with the DEBUG environment variable set to &quot;electron-rebuild&quot;.
    6Error: `gyp` failed with exit code: 1
    7Error: node-gyp failed to rebuild '/home/pi/ma-0042-cihaz-be/node_modules/epoll'.
    8For more information, rerun with the DEBUG environment variable set to &quot;electron-rebuild&quot;.
    9at NodeGyp.rebuildModule (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/module-type/node-gyp.js:109:19)
    10    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    11    at async ModuleRebuilder.rebuildNodeGypModule (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/module-rebuilder.js:94:9)
    12    at async Rebuilder.rebuildModuleAt (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/rebuild.js:226:9)
    13    at async Rebuilder.rebuild (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/rebuild.js:184:17)
    14    at async /home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/cli.js:154:9
    15
    16

    I am using a raspberry, I did update it too. But it didn't work. These are the dependencies installed.

    1Building module: epoll, Completed: 0gyp: name 'openssl_fips' is not defined while evaluating condition 'openssl_fips != &quot;&quot;' in binding.gyp while trying to load binding.gyp
    2✖ Rebuild Failed
    3An unhandled error occurred inside electron-rebuild
    4node-gyp failed to rebuild '/home/pi/ma-0042-cihaz-be/node_modules/epoll'.
    5For more information, rerun with the DEBUG environment variable set to &quot;electron-rebuild&quot;.
    6Error: `gyp` failed with exit code: 1
    7Error: node-gyp failed to rebuild '/home/pi/ma-0042-cihaz-be/node_modules/epoll'.
    8For more information, rerun with the DEBUG environment variable set to &quot;electron-rebuild&quot;.
    9at NodeGyp.rebuildModule (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/module-type/node-gyp.js:109:19)
    10    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    11    at async ModuleRebuilder.rebuildNodeGypModule (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/module-rebuilder.js:94:9)
    12    at async Rebuilder.rebuildModuleAt (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/rebuild.js:226:9)
    13    at async Rebuilder.rebuild (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/rebuild.js:184:17)
    14    at async /home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/cli.js:154:9
    15
    16{
    17 
    18  &quot;dependencies&quot;: {
    19    &quot;@babel/preset-react&quot;: &quot;^7.14.5&quot;,
    20    &quot;bcryptjs&quot;: &quot;^2.4.3&quot;,
    21    &quot;body-parser&quot;: &quot;^1.19.0&quot;,
    22    &quot;cors&quot;: &quot;^2.8.5&quot;,
    23    &quot;dotenv&quot;: &quot;^10.0.0&quot;,
    24    &quot;express&quot;: &quot;^4.17.1&quot;,
    25    &quot;history&quot;: &quot;^5.1.0&quot;,
    26    &quot;i2c-bus&quot;: &quot;^5.2.2&quot;,
    27    &quot;jest&quot;: &quot;^27.3.1&quot;,
    28    &quot;jest-fetch-mock&quot;: &quot;^3.0.3&quot;,
    29    &quot;jsonwebtoken&quot;: &quot;^8.5.1&quot;,
    30    &quot;mfrc522-rpi&quot;: &quot;^2.1.3&quot;,
    31    &quot;moment&quot;: &quot;^2.29.1&quot;,
    32    &quot;network-config&quot;: &quot;^3.0.0&quot;,
    33    &quot;node-cron&quot;: &quot;^3.0.0&quot;,
    34    &quot;node-fetch&quot;: &quot;^2.6.5&quot;,
    35    &quot;node-wifi&quot;: &quot;^2.0.15&quot;,
    36    &quot;pi-camera&quot;: &quot;^1.6.0&quot;,
    37    &quot;react&quot;: &quot;^17.0.2&quot;,
    38    &quot;react-dom&quot;: &quot;^17.0.2&quot;,
    39    &quot;react-router-dom&quot;: &quot;^6.0.0&quot;,
    40    &quot;realm&quot;: &quot;^10.7.0&quot;,
    41    &quot;rpi-gpio&quot;: &quot;^2.1.7&quot;,
    42    &quot;rpi-softspi&quot;: &quot;^1.0.5&quot;,
    43    &quot;rpio&quot;: &quot;^2.4.2&quot;,
    44    &quot;source-map-support&quot;: &quot;^0.5.16&quot;
    45  },
    46  &quot;devDependencies&quot;: {
    47    &quot;@babel/core&quot;: &quot;^7.15.5&quot;,
    48    &quot;@babel/node&quot;: &quot;^7.15.4&quot;,
    49    &quot;@babel/plugin-transform-runtime&quot;: &quot;^7.16.0&quot;,
    50    &quot;@babel/preset-env&quot;: &quot;^7.15.6&quot;,
    51    &quot;babel-loader&quot;: &quot;^8.2.2&quot;,
    52    &quot;electron&quot;: &quot;8.2.0&quot;,
    53    &quot;electron-builder&quot;: &quot;^22.11.7&quot;,
    54    &quot;electron-rebuild&quot;: &quot;^3.2.3&quot;,
    55    &quot;electron-webpack&quot;: &quot;^2.8.2&quot;,
    56    &quot;enzyme&quot;: &quot;^3.11.0&quot;,
    57    &quot;enzyme-adapter-react-16&quot;: &quot;^1.15.6&quot;,
    58    &quot;enzyme-to-json&quot;: &quot;^3.6.2&quot;,
    59    &quot;webpack&quot;: &quot;~4.42.1&quot;
    60  }
    61}
    62

    I deleted node_modules with package-lock.json and installed everything again. I updated the raspberry with apt-get upgrade. I don't know how can I solve this issue. Do you have any ideas?

    ANSWER

    Answered 2021-Nov-09 at 06:01

    I have a same problem too, but i am using a serialport not epoll.

    So, I think the cause of this problem is electron modules not the native module.

    1Building module: epoll, Completed: 0gyp: name 'openssl_fips' is not defined while evaluating condition 'openssl_fips != &quot;&quot;' in binding.gyp while trying to load binding.gyp
    2✖ Rebuild Failed
    3An unhandled error occurred inside electron-rebuild
    4node-gyp failed to rebuild '/home/pi/ma-0042-cihaz-be/node_modules/epoll'.
    5For more information, rerun with the DEBUG environment variable set to &quot;electron-rebuild&quot;.
    6Error: `gyp` failed with exit code: 1
    7Error: node-gyp failed to rebuild '/home/pi/ma-0042-cihaz-be/node_modules/epoll'.
    8For more information, rerun with the DEBUG environment variable set to &quot;electron-rebuild&quot;.
    9at NodeGyp.rebuildModule (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/module-type/node-gyp.js:109:19)
    10    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    11    at async ModuleRebuilder.rebuildNodeGypModule (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/module-rebuilder.js:94:9)
    12    at async Rebuilder.rebuildModuleAt (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/rebuild.js:226:9)
    13    at async Rebuilder.rebuild (/home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/rebuild.js:184:17)
    14    at async /home/pi/ma-0042-cihaz-be/node_modules/electron-rebuild/lib/src/cli.js:154:9
    15
    16{
    17 
    18  &quot;dependencies&quot;: {
    19    &quot;@babel/preset-react&quot;: &quot;^7.14.5&quot;,
    20    &quot;bcryptjs&quot;: &quot;^2.4.3&quot;,
    21    &quot;body-parser&quot;: &quot;^1.19.0&quot;,
    22    &quot;cors&quot;: &quot;^2.8.5&quot;,
    23    &quot;dotenv&quot;: &quot;^10.0.0&quot;,
    24    &quot;express&quot;: &quot;^4.17.1&quot;,
    25    &quot;history&quot;: &quot;^5.1.0&quot;,
    26    &quot;i2c-bus&quot;: &quot;^5.2.2&quot;,
    27    &quot;jest&quot;: &quot;^27.3.1&quot;,
    28    &quot;jest-fetch-mock&quot;: &quot;^3.0.3&quot;,
    29    &quot;jsonwebtoken&quot;: &quot;^8.5.1&quot;,
    30    &quot;mfrc522-rpi&quot;: &quot;^2.1.3&quot;,
    31    &quot;moment&quot;: &quot;^2.29.1&quot;,
    32    &quot;network-config&quot;: &quot;^3.0.0&quot;,
    33    &quot;node-cron&quot;: &quot;^3.0.0&quot;,
    34    &quot;node-fetch&quot;: &quot;^2.6.5&quot;,
    35    &quot;node-wifi&quot;: &quot;^2.0.15&quot;,
    36    &quot;pi-camera&quot;: &quot;^1.6.0&quot;,
    37    &quot;react&quot;: &quot;^17.0.2&quot;,
    38    &quot;react-dom&quot;: &quot;^17.0.2&quot;,
    39    &quot;react-router-dom&quot;: &quot;^6.0.0&quot;,
    40    &quot;realm&quot;: &quot;^10.7.0&quot;,
    41    &quot;rpi-gpio&quot;: &quot;^2.1.7&quot;,
    42    &quot;rpi-softspi&quot;: &quot;^1.0.5&quot;,
    43    &quot;rpio&quot;: &quot;^2.4.2&quot;,
    44    &quot;source-map-support&quot;: &quot;^0.5.16&quot;
    45  },
    46  &quot;devDependencies&quot;: {
    47    &quot;@babel/core&quot;: &quot;^7.15.5&quot;,
    48    &quot;@babel/node&quot;: &quot;^7.15.4&quot;,
    49    &quot;@babel/plugin-transform-runtime&quot;: &quot;^7.16.0&quot;,
    50    &quot;@babel/preset-env&quot;: &quot;^7.15.6&quot;,
    51    &quot;babel-loader&quot;: &quot;^8.2.2&quot;,
    52    &quot;electron&quot;: &quot;8.2.0&quot;,
    53    &quot;electron-builder&quot;: &quot;^22.11.7&quot;,
    54    &quot;electron-rebuild&quot;: &quot;^3.2.3&quot;,
    55    &quot;electron-webpack&quot;: &quot;^2.8.2&quot;,
    56    &quot;enzyme&quot;: &quot;^3.11.0&quot;,
    57    &quot;enzyme-adapter-react-16&quot;: &quot;^1.15.6&quot;,
    58    &quot;enzyme-to-json&quot;: &quot;^3.6.2&quot;,
    59    &quot;webpack&quot;: &quot;~4.42.1&quot;
    60  }
    61}
    62yarn run v1.22.15
    63$ electron-rebuild -f -w myapp
    64\ Building module: bindings, Completed: 0gyp: name 'openssl_fips' is not defined while evaluating condition 'openssl_fips != ""' in binding.gyp while trying to load binding.gyp
    65× Rebuild Failed
    66
    67An unhandled error occurred inside electron-rebuild
    68node-gyp failed to rebuild 'C:\Users\node_modules\@serialport\bindings'.
    69For more information, rerun with the DEBUG environment variable set to "electron-rebuild".
    70
    71Error: `gyp` failed with exit code: 1
    72
    73
    74
    75Error: node-gyp failed to rebuild 'C:\Users\node_modules\@serialport\bindings'.
    76For more information, rerun with the DEBUG environment variable set to "electron-rebuild".
    77
    78Error: `gyp` failed with exit code: 1
    79
    80
    81    at NodeGyp.rebuildModule (C:\Users\node_modules\electron-rebuild\lib\src\module-type\node-gyp.js:109:19)
    82    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    83    at async ModuleRebuilder.rebuildNodeGypModule (C:\Users\node_modules\electron-rebuild\lib\src\module-rebuilder.js:94:9)
    84    at async Rebuilder.rebuildModuleAt (C:\Users\node_modules\electron-rebuild\lib\src\rebuild.js:226:9)
    85    at async Rebuilder.rebuild (C:\Users\node_modules\electron-rebuild\lib\src\rebuild.js:184:17)
    86    at async C:\Users\node_modules\electron-rebuild\lib\src\cli.js:154:9
    87error Command failed with exit code 4294967295.
    88info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

    This problem started yesterday. There were no problems in the last week.

    I already installed the windows-build-tools, node-gyp, python 3.x.

    I set the npm config & yarn config & python Env path, msvs_version too.

    I reinstalled above packages many many times but not work electron-rebuild.

    That is whole Error messages. There is no more Error messages.

    What should we do?

    Source https://stackoverflow.com/questions/69882740

    QUESTION

    How to get a response from the async write function in capacitor-community / bluetooth-le

    Asked 2022-Mar-18 at 01:42

    I'm working with an ESP32 chip and am trying to create an Android app (using Ionic) which allows user to send wifi credentials to the ESP32 chip via BLE. I'd like to be able to update the status of the wifi sending process for the user in the UI (which I'm developing using Angular and then converting it to an Android webapp using Ionic). To do this, I'm also using the capacitor-community/bluetooth-le library.

    Can anyone explain to me what this.queue does in the async write function (code shown below) does? I thought this function returns a response from a remote BLE device after writing to a GATT characteristic, but I get absolutely nothing at all for a response.

    1async write(deviceId: string, service: string, characteristic: string, value: DataView): Promise&lt;void&gt; {
    2    service = validateUUID(service);
    3    characteristic = validateUUID(characteristic);
    4    return this.queue(async () =&gt; {
    5      if (!value?.buffer) {
    6        throw new Error('Invalid data.');
    7      }
    8      let writeValue: DataView | string = value;
    9      if (Capacitor.getPlatform() !== 'web') {
    10        // on native we can only write strings
    11        writeValue = dataViewToHexString(value);
    12      }
    13      await BluetoothLe.write({
    14        deviceId,
    15        service,
    16        characteristic,
    17        value: writeValue,
    18      });
    19    });
    20  }
    21

    Here's how I'm using the write function shown above:

    1async write(deviceId: string, service: string, characteristic: string, value: DataView): Promise&lt;void&gt; {
    2    service = validateUUID(service);
    3    characteristic = validateUUID(characteristic);
    4    return this.queue(async () =&gt; {
    5      if (!value?.buffer) {
    6        throw new Error('Invalid data.');
    7      }
    8      let writeValue: DataView | string = value;
    9      if (Capacitor.getPlatform() !== 'web') {
    10        // on native we can only write strings
    11        writeValue = dataViewToHexString(value);
    12      }
    13      await BluetoothLe.write({
    14        deviceId,
    15        service,
    16        characteristic,
    17        value: writeValue,
    18      });
    19    });
    20  }
    21this.bleConnectService.getBLE().then(resp =&gt; {
    22  this.deviceID = resp});
    23}
    24
    25BleClient.write(this.deviceID, '021a9004-0382-4aea-bff4-6b3f1c5adfb4', '021aff54-0382-4aea-bff4-6b3f1c5adfb4', bytesOfStuff).then(resp =&gt; {
    26      const result2 = resp;
    27}
    28

    I know for a fact that the write function works because my chip is getting the data I'm sending in the right format. I'm just not getting a response back on the client side from the write function. Also, I can confirm the chip is sending a response each time it does something with the data I send to it.

    ANSWER

    Answered 2022-Mar-18 at 01:42

    Here's how I'm using BleClient.write to transmit information to a BLE device (recipient):

    1async write(deviceId: string, service: string, characteristic: string, value: DataView): Promise&lt;void&gt; {
    2    service = validateUUID(service);
    3    characteristic = validateUUID(characteristic);
    4    return this.queue(async () =&gt; {
    5      if (!value?.buffer) {
    6        throw new Error('Invalid data.');
    7      }
    8      let writeValue: DataView | string = value;
    9      if (Capacitor.getPlatform() !== 'web') {
    10        // on native we can only write strings
    11        writeValue = dataViewToHexString(value);
    12      }
    13      await BluetoothLe.write({
    14        deviceId,
    15        service,
    16        characteristic,
    17        value: writeValue,
    18      });
    19    });
    20  }
    21this.bleConnectService.getBLE().then(resp =&gt; {
    22  this.deviceID = resp});
    23}
    24
    25BleClient.write(this.deviceID, '021a9004-0382-4aea-bff4-6b3f1c5adfb4', '021aff54-0382-4aea-bff4-6b3f1c5adfb4', bytesOfStuff).then(resp =&gt; {
    26      const result2 = resp;
    27}
    28BleClient.write(this.connectedDevice.deviceId, this.baseUUID, this.characteristicUUID, data)
    29.then(console.log('BleWrite was successful.  Now let/'s do something else')
    30.catch(error =&gt; console.log('BleWrite fail error: ', error))
    31

    BleClient.write returns undefined (promise) when resolved. So when it resolves (ie, BleClient.write is successful), it doesn't fetch and return any confirming data from the recipient device it writes to. You could say the absence of an error implies BleClient.write was successful. If BleClient.write rejects, it will return an error.

    But just because BleClient.write resolves doesn't mean that the recipient device received and recorded the information at its end. If there's a connection breakdown between the initiating and recipient devices, BleClient.write may very well have completed its share of the transmission and resolved, but the recipient device may still not have received the data. To make sure your recipient device gets the data as intended, there has to be some logic at the recipient device's end to process the incoming data and write something to its own GATT characteristic indicating successful receipt of data from the initiating device. The initiating device can then read this information from the recipient device's GATT characteristic using BleClient.read() to get confirmation that the recipient device did in fact get the data.

    Source https://stackoverflow.com/questions/70366455

    QUESTION

    Android Studio Disconnects From Physical Device

    Asked 2022-Mar-06 at 15:11

    Android Studio Bumblebee (2021.1.1) was released stably on 25 January 2022 bundled with a new Device Manager (accompanying new support for Android 11+ device debugging over WIFI). I jumped on this stable release, updating from Android Studio Arctic Fox (2020.3.1 Patch 4).

    Unfortunately however, since updating, physical devices/handsets don't remain connected to Android Studio for the purpose of debugging. I can confirm that the issue was introduced from Android Studio Bumblebee onwards (occurring in Beta and Canary builds also). I've reproduced the issue on Android Studio Bumblebee (Stable), Chipmunk (Beta), and Dolphin (Canary), but Android Studio Arctic Fox (superseded Stable) continues to work just fine.

    The issue occurs soon after opening Android Studio (Bumblebee+) with one of my physical devices connected. Everything appears fine initially and I may even have enough time to deploy my project to the handset, before the device disappears from Android Studio (as if I'd physically disconnected the USB cable from my computer or from the handset itself).

    I've tried a fair few things in an attempt to determine a root cause. These include testing:

    • With different USB cables.
    • With different handsets (both varying makes and models).
    • With various versions of the Android Studio IDE (as mentioned above).
    • Plugging the USB cables into different USB ports on my computer.
    • Rebooting handsets and my computer.
    • Restarting Android Studio.
    • Invalidating caches and restarting Android Studio.
    • adb kill-server then adb start-server.
    • Revoking/reaccepting USB debugging authorization.
    • Reinstalled build tools/platform tools, and ADB.
    • A great number of further possibilities, to no avail.

    I searched and read through remotely similar issues, including (but not limited to) these:

    This particular comment in one of the above issues clued me onto a possible root cause:

    I have been fighting for a few days with adb not seeing my device. After trying many other posted solutions, I discovered that the issue was with Chrome also trying to connect its debugger to a web view. If Chrome is connected using chrome://inspect, then adb seems to disconnect. Quitting Chrome resolves the issue. Then I can connect with Android Studio and then restart Chrome and reconnect. Hope this helps someone else.

    However I've been unable to do anything with the above discovery, other than close Google Chrome, and hope for the best. Obviously this isn't an ideal solution. It appears as though the moment Google Chrome shows the connected physical device in the chrome://inspect/#devices page, the physical device promptly becomes unavailable through Android Studio.

    I've jumped back to Android Studio Arctic Fox (2020.3.1 Patch 4) for the moment, however this brings with it other issues (my current core project targets the latest SDK version, which requires the updated IDE).

    Absolutely any help with this would be insanely appreciated. I've exhausted just about every avenue that I can think of!

    ANSWER

    Answered 2022-Feb-01 at 17:29

    I solved the problem by disabling

    Settings -> Build, Execution, Deployment -> Debugger -> "Enable adb mDNS for wireless debugging"

    Source https://stackoverflow.com/questions/70936120

    QUESTION

    Winsock sendto returns error 10049 (WSAEADDRNOTAVAIL) for broadcast address after network adapter is disabled or physically disconnected

    Asked 2022-Mar-01 at 16:10

    I am working on a p2p application and to make testing simple, I am currently using udp broadcast for the peer discovery in my local network. Each peer binds one udp socket to port 29292 of the ip address of each local network interface (discovered via GetAdaptersInfo) and each socket periodically sends a packet to the broadcast address of its network interface/local address. The sockets are set to allow port reuse (via setsockopt SO_REUSEADDR), which enables me to run multiple peers on the same local machine without any conflicts. In this case there is only a single peer on the entire network though.

    This all works perfectly fine (tested with 2 peers on 1 machine and 2 peers on 2 machines) UNTIL a network interface is disconnected. When deactivacting the network adapter of either my wifi or an USB-to-LAN adapter in the windows dialog, or just plugging the usb cable of the adapter, the next call to sendto will fail with return code 10049. It doesn't matter if the other adapter is still connected, or was at the beginning, it will fail. The only thing that doesn't make it fail is deactivating wifi through the fancy win10 dialog through the taskbar, but that isn't really a surprise because that doesn't deactivate or remove the adapter itself.

    I initially thought that this makes sense because when the nic is gone, how should the system route the packet. But: The fact that the packet can't reach its target has absolutely nothing to do with the address itsself being invalid (which is what the error means), so I suspect I am missing something here. I was looking for any information I could use to detect this case and distinguish it from simply trying to sendto INADDR_ANY, but I couldn't find anything. I started to log every bit of information which I suspected could have changed, but its all the same on a successfull sendto and the one that crashes (retrieved via getsockopt):

    1250   16.24746[886] [debug|debug] local address: 192.168.178.35
    2251   16.24812[886] [debug|debug] no remote address
    3252   16.25333[886] [debug|debug] type: SOCK_DGRAM
    4253   16.25457[886] [debug|debug] protocol: IPPROTO_UDP
    5254   16.25673[886] [debug|debug] broadcast: 1, dontroute: 0, max_msg_size: 65507, rcv_buffer: 65536, rcv_timeout: 0, reuse_addr: 1, snd_buffer: 65536, sdn_timeout: 0
    6255   16.25806[886] [debug|debug] Last WSA error on socket was WSA Error Code 0: The operation completed successfully.
    7
    8256   16.25916[886] [debug|debug] target address windows formatted: 192.168.178.255
    9257   16.25976[886] [debug|debug] target address 192.168.178.255:29292
    10258   16.26138[886] [debug|assert] ASSERT FAILED at D:\Workspaces\spaced\source\platform\win32_platform.cpp:4141: sendto failed with (unhandled) WSA Error Code 10049: The requested address is not valid in its context.
    11

    The nic that got removed is this one:

    1250   16.24746[886] [debug|debug] local address: 192.168.178.35
    2251   16.24812[886] [debug|debug] no remote address
    3252   16.25333[886] [debug|debug] type: SOCK_DGRAM
    4253   16.25457[886] [debug|debug] protocol: IPPROTO_UDP
    5254   16.25673[886] [debug|debug] broadcast: 1, dontroute: 0, max_msg_size: 65507, rcv_buffer: 65536, rcv_timeout: 0, reuse_addr: 1, snd_buffer: 65536, sdn_timeout: 0
    6255   16.25806[886] [debug|debug] Last WSA error on socket was WSA Error Code 0: The operation completed successfully.
    7
    8256   16.25916[886] [debug|debug] target address windows formatted: 192.168.178.255
    9257   16.25976[886] [debug|debug] target address 192.168.178.255:29292
    10258   16.26138[886] [debug|assert] ASSERT FAILED at D:\Workspaces\spaced\source\platform\win32_platform.cpp:4141: sendto failed with (unhandled) WSA Error Code 10049: The requested address is not valid in its context.
    11   1.07254[0] [platform|info] Discovered Network Interface &quot;Realtek USB GbE Family Controller&quot; with IP 192.168.178.35 and Subnet 255.255.255.0
    12

    And this is the code that does the sending (dlog_socket_information_and_last_wsaerror generates all the output that is gathered using getsockopt):

    1250   16.24746[886] [debug|debug] local address: 192.168.178.35
    2251   16.24812[886] [debug|debug] no remote address
    3252   16.25333[886] [debug|debug] type: SOCK_DGRAM
    4253   16.25457[886] [debug|debug] protocol: IPPROTO_UDP
    5254   16.25673[886] [debug|debug] broadcast: 1, dontroute: 0, max_msg_size: 65507, rcv_buffer: 65536, rcv_timeout: 0, reuse_addr: 1, snd_buffer: 65536, sdn_timeout: 0
    6255   16.25806[886] [debug|debug] Last WSA error on socket was WSA Error Code 0: The operation completed successfully.
    7
    8256   16.25916[886] [debug|debug] target address windows formatted: 192.168.178.255
    9257   16.25976[886] [debug|debug] target address 192.168.178.255:29292
    10258   16.26138[886] [debug|assert] ASSERT FAILED at D:\Workspaces\spaced\source\platform\win32_platform.cpp:4141: sendto failed with (unhandled) WSA Error Code 10049: The requested address is not valid in its context.
    11   1.07254[0] [platform|info] Discovered Network Interface &quot;Realtek USB GbE Family Controller&quot; with IP 192.168.178.35 and Subnet 255.255.255.0
    12void send_slice_over_udp_socket(Socket_Handle handle, Slice&lt;d_byte&gt; buffer, u32 remote_ip, u16 remote_port){
    13    PROFILE_FUNCTION();
    14
    15    auto socket = (UDP_Socket*) sockets[handle.handle];
    16    ASSERT_VALID_UDP_SOCKET(socket);
    17    dlog_socket_information_and_last_wsaerror(socket);
    18
    19    if(socket-&gt;is_dummy)
    20        return;
    21
    22    if(buffer.size == 0)
    23        return;
    24
    25    DASSERT(socket-&gt;state == Socket_State::created);
    26
    27    u64 bytes_left = buffer.size;
    28
    29    sockaddr_in target_socket_address = create_socket_address(remote_ip, remote_port);
    30
    31    #pragma warning(push)
    32    #pragma warning(disable: 4996)
    33    dlog(&quot;target address windows formatted: %s&quot;, inet_ntoa(target_socket_address.sin_addr));
    34    #pragma warning(pop)
    35    unsigned char* parts = (unsigned char*)&amp;remote_ip;
    36    dlog(&quot;target address %hhu.%hhu.%hhu.%hhu:%hu&quot;, parts[3], parts[2], parts[1], parts[0], remote_port);
    37
    38    int sent_bytes = sendto(socket-&gt;handle, (char*) buffer.data, bytes_left &gt; (u64) INT32_MAX ? INT32_MAX : (int) bytes_left, 0, (sockaddr*)&amp;target_socket_address, sizeof(target_socket_address));
    39
    40    if(sent_bytes == SOCKET_ERROR){
    41        #define LOG_WARNING(message) log_nonreproducible(message, Category::platform_network, Severity::warning, socket-&gt;handle); return;
    42        switch(WSAGetLastError()){
    43            //@TODO handle all (more? I guess many should just be asserted since they should never happen) cases
    44            case WSAEHOSTUNREACH: LOG_WARNING(&quot;socket %lld, send failed: The remote host can't be reached at this time.&quot;);
    45            case WSAECONNRESET: LOG_WARNING(&quot;socket %lld, send failed: Multiple UDP packet deliveries failed. According to documentation we should close the socket. Not sure if this makes sense, this is a UDP port after all. Closing the socket wont change anything, right?&quot;);
    46            case WSAENETUNREACH: LOG_WARNING(&quot;socket %lld, send failed: the network cannot be reached from this host at this time.&quot;);
    47            case WSAETIMEDOUT: LOG_WARNING(&quot;socket %lld, send failed: The connection has been dropped, because of a network failure or because the system on the other end went down without notice.&quot;);
    48
    49            case WSAEADDRNOTAVAIL:
    50
    51            case WSAENETRESET:
    52            case WSAEACCES:
    53            case WSAEWOULDBLOCK: //can this even happen on a udp port? I expect this to be fire-and-forget-style.
    54            case WSAEMSGSIZE:
    55            case WSANOTINITIALISED:
    56            case WSAENETDOWN:
    57            case WSAEINVAL:
    58            case WSAEINTR:
    59            case WSAEINPROGRESS:
    60            case WSAEFAULT:
    61            case WSAENOBUFS:
    62            case WSAENOTCONN:
    63            case WSAENOTSOCK:
    64            case WSAEOPNOTSUPP:
    65            case WSAESHUTDOWN:
    66            case WSAECONNABORTED:
    67            case WSAEAFNOSUPPORT:
    68            case WSAEDESTADDRREQ:
    69                ASSERT(false, tprint_last_wsa_error_as_formatted_message(&quot;sendto failed with (unhandled) &quot;)); break;
    70            default: ASSERT(false, tprint_last_wsa_error_as_formatted_message(&quot;sendto failed with (undocumented) &quot;)); //The switch case above should have been exhaustive. This is a bug. We either forgot a case, or maybe the docs were lying? (That happened to me on android. Fun times. Well. Not really.)
    71        }
    72        #undef LOG_WARNING
    73    }
    74
    75    DASSERT(sent_bytes &gt;= 0);
    76    total_bytes_sent += (u64) sent_bytes;
    77    bytes_left -= (u64) sent_bytes;
    78    DASSERT(bytes_left == 0);
    79}
    80

    The code that generates the address from ip and port looks like this:

    1250   16.24746[886] [debug|debug] local address: 192.168.178.35
    2251   16.24812[886] [debug|debug] no remote address
    3252   16.25333[886] [debug|debug] type: SOCK_DGRAM
    4253   16.25457[886] [debug|debug] protocol: IPPROTO_UDP
    5254   16.25673[886] [debug|debug] broadcast: 1, dontroute: 0, max_msg_size: 65507, rcv_buffer: 65536, rcv_timeout: 0, reuse_addr: 1, snd_buffer: 65536, sdn_timeout: 0
    6255   16.25806[886] [debug|debug] Last WSA error on socket was WSA Error Code 0: The operation completed successfully.
    7
    8256   16.25916[886] [debug|debug] target address windows formatted: 192.168.178.255
    9257   16.25976[886] [debug|debug] target address 192.168.178.255:29292
    10258   16.26138[886] [debug|assert] ASSERT FAILED at D:\Workspaces\spaced\source\platform\win32_platform.cpp:4141: sendto failed with (unhandled) WSA Error Code 10049: The requested address is not valid in its context.
    11   1.07254[0] [platform|info] Discovered Network Interface &quot;Realtek USB GbE Family Controller&quot; with IP 192.168.178.35 and Subnet 255.255.255.0
    12void send_slice_over_udp_socket(Socket_Handle handle, Slice&lt;d_byte&gt; buffer, u32 remote_ip, u16 remote_port){
    13    PROFILE_FUNCTION();
    14
    15    auto socket = (UDP_Socket*) sockets[handle.handle];
    16    ASSERT_VALID_UDP_SOCKET(socket);
    17    dlog_socket_information_and_last_wsaerror(socket);
    18
    19    if(socket-&gt;is_dummy)
    20        return;
    21
    22    if(buffer.size == 0)
    23        return;
    24
    25    DASSERT(socket-&gt;state == Socket_State::created);
    26
    27    u64 bytes_left = buffer.size;
    28
    29    sockaddr_in target_socket_address = create_socket_address(remote_ip, remote_port);
    30
    31    #pragma warning(push)
    32    #pragma warning(disable: 4996)
    33    dlog(&quot;target address windows formatted: %s&quot;, inet_ntoa(target_socket_address.sin_addr));
    34    #pragma warning(pop)
    35    unsigned char* parts = (unsigned char*)&amp;remote_ip;
    36    dlog(&quot;target address %hhu.%hhu.%hhu.%hhu:%hu&quot;, parts[3], parts[2], parts[1], parts[0], remote_port);
    37
    38    int sent_bytes = sendto(socket-&gt;handle, (char*) buffer.data, bytes_left &gt; (u64) INT32_MAX ? INT32_MAX : (int) bytes_left, 0, (sockaddr*)&amp;target_socket_address, sizeof(target_socket_address));
    39
    40    if(sent_bytes == SOCKET_ERROR){
    41        #define LOG_WARNING(message) log_nonreproducible(message, Category::platform_network, Severity::warning, socket-&gt;handle); return;
    42        switch(WSAGetLastError()){
    43            //@TODO handle all (more? I guess many should just be asserted since they should never happen) cases
    44            case WSAEHOSTUNREACH: LOG_WARNING(&quot;socket %lld, send failed: The remote host can't be reached at this time.&quot;);
    45            case WSAECONNRESET: LOG_WARNING(&quot;socket %lld, send failed: Multiple UDP packet deliveries failed. According to documentation we should close the socket. Not sure if this makes sense, this is a UDP port after all. Closing the socket wont change anything, right?&quot;);
    46            case WSAENETUNREACH: LOG_WARNING(&quot;socket %lld, send failed: the network cannot be reached from this host at this time.&quot;);
    47            case WSAETIMEDOUT: LOG_WARNING(&quot;socket %lld, send failed: The connection has been dropped, because of a network failure or because the system on the other end went down without notice.&quot;);
    48
    49            case WSAEADDRNOTAVAIL:
    50
    51            case WSAENETRESET:
    52            case WSAEACCES:
    53            case WSAEWOULDBLOCK: //can this even happen on a udp port? I expect this to be fire-and-forget-style.
    54            case WSAEMSGSIZE:
    55            case WSANOTINITIALISED:
    56            case WSAENETDOWN:
    57            case WSAEINVAL:
    58            case WSAEINTR:
    59            case WSAEINPROGRESS:
    60            case WSAEFAULT:
    61            case WSAENOBUFS:
    62            case WSAENOTCONN:
    63            case WSAENOTSOCK:
    64            case WSAEOPNOTSUPP:
    65            case WSAESHUTDOWN:
    66            case WSAECONNABORTED:
    67            case WSAEAFNOSUPPORT:
    68            case WSAEDESTADDRREQ:
    69                ASSERT(false, tprint_last_wsa_error_as_formatted_message(&quot;sendto failed with (unhandled) &quot;)); break;
    70            default: ASSERT(false, tprint_last_wsa_error_as_formatted_message(&quot;sendto failed with (undocumented) &quot;)); //The switch case above should have been exhaustive. This is a bug. We either forgot a case, or maybe the docs were lying? (That happened to me on android. Fun times. Well. Not really.)
    71        }
    72        #undef LOG_WARNING
    73    }
    74
    75    DASSERT(sent_bytes &gt;= 0);
    76    total_bytes_sent += (u64) sent_bytes;
    77    bytes_left -= (u64) sent_bytes;
    78    DASSERT(bytes_left == 0);
    79}
    80sockaddr_in create_socket_address(u32 ip, u16 port){
    81    sockaddr_in address_info;
    82    address_info.sin_family = AF_INET;
    83    address_info.sin_port = htons(port);
    84    address_info.sin_addr.s_addr = htonl(ip);
    85    memset(address_info.sin_zero, 0, 8);
    86    return address_info;
    87}
    88

    The error seems to be a little flaky. It reproduces 100% of the time until it decides not to anymore. After a restart its usually back.

    I am looking for a solution to handle this case correctly. I could of course just re-do the network interface discovery when the error occurs, because I "know" that I don't give any broken IPs to sendto, but that would just be a heuristic. I want to solve the actual problem.

    I also don't quite understand when error 10049 is supposed to fire exactly anyway. Is it just if I pass an ipv6 address to a ipv4 socket, or send to 0.0.0.0? There is no flat out "illegal" ipv4 address after all, just ones that don't make sense from context.

    If you know what I am missing here, please let me know!

    ANSWER

    Answered 2022-Mar-01 at 16:01

    This is a issue people have been facing up for a while , and people suggested to read the documentation provided by Microsoft on the following issue . "Btw , I don't know whether they are the same issues or not but the error thrown back the code are same, that's why I have attached a link for the same!!"

    https://docs.microsoft.com/en-us/answers/questions/537493/binding-winsock-shortly-after-boot-results-in-erro.html

    Source https://stackoverflow.com/questions/71196378

    QUESTION

    Compress &amp; Upload large videos to Google cloud storage using Flutter/Dart

    Asked 2022-Feb-20 at 03:41

    There are a couple of notable packages on pub.dev that offer video compression. I've tried them, and other sketchy packages, and none work well once a video gets around 300MB. They crash or have other issues on various platforms and hardware. Namely, video compress and light compressor. The GH commits and support are concerning as well on the packages I've seen for video compression in pub.dev. PR's not being pulled in and issues not being resolved in a timely manner and some quite serious for recent android APK updates. So not something I want in my dependency stack.

    I am uploading to Google Cloud Storage using FlutterFire. While my code does upload using FireBaseStorage upload task it does not have any ability to compress on the client side or handle background uploading when the app is closed.

    So, currently on the server side, I have a GCF that triggers on file uploaded. Then I use nodejs ffmpeg, which is baked into GCF's to compress server side and convert to H264. And finally delete the original large upload video and save the compressed video to storage.

    This solution works, but depending on a user's connection and whether they are on wifi, can take an awful long time and when it fails or the user closes the app, my current solution is useless.

    I wish there was a solid native library on Android and iOS, that I could tap into, to confidently perform compression and conversion from any format to H264 and also allow uploading, whether my app is closed or in the background, to GC storage. Any thoughts? I wish this was standard in FlutterFire's cloud storage handling!

    I have yet to test flutter_ffmpeg, but only because some have said it runs so slowly on client. So again, Flutter/Dart can access natively written code, but I don't know where to start on Android/iOS to do this the right way. And I understand this is what some of the packages are doing, but they do not work with large videos, so I'm hoping someone can point me in the right direction on Android and iOS.

    My code for handling upload tasks to GC storage.

    1 
    2 ​  ​Future&lt;​void​&gt;​ ​uploadTask​({ 
    3 ​    ​required​ ​WidgetRef​ ref, 
    4 ​    ​required​ ​File​ file, 
    5 ​    ​required​ ​String​ objectPath, 
    6 ​    ​SettableMetadata​?​ metaData, 
    7 ​    ​bool​ deleteAfterUpload ​=​ ​false​, 
    8 ​    ​bool​ displayProgressNotification ​=​ ​false​, 
    9 ​  }) ​async​ { 
    10 ​    ​String​ filePath ​=​ file.path; 
    11 ​    filename ​=​ ​basename​(file.path); 
    12  
    13 ​    ​/// Remove any instances of '//' from the path. 
    14 ​    ​final​ ​String​ path ​=​ ​'$​storagePath​/$​objectPath​'​.​replaceAll​(​'//'​, ​'/'​); 
    15 ​    ​UploadTask​ task ​=​ storage.​ref​(path).​putFile​( 
    16 ​          ​File​(filePath), 
    17 ​          metaData, 
    18 ​        ); 
    19  
    20 ​    ​/// Store UploadTask in StateNotifierProvider to monitor progress. 
    21 ​    ref.​read​(uploadingStateProvider.notifier).​myUploadTask​(task); 
    22 ​  }
    23

    ANSWER

    Answered 2022-Feb-20 at 03:41

    I did resolve, to some degree, my original post's questions and frustrations by using the ffmpeg_kit_flutter_full_gpl package on the client side, and then ffmpeg again in GCF on the server side. In summary:

    • Within 60 seconds, I can now compress a 2 minute video by 90% before uploading to firebase storage.
    • Using onFinalize via GCF on the server side I run ffmpeg again on the uploaded video and gain another 77% reduction in file size on the server side without any loss in video quality.
    • My solution does not yet upload while the app is closed.
    • On the client side, this solution requires setting the camera ResolutionPreset to high (720p), rather than max, which can be a minimum of 1080p, and setting the ffmpeg -preset veryfast rather than the medium default.

    Camera & ffmpeg solution settings:

    Transcoding results stats for 2 minute video:

    • Before transcode: 255MB
    • After client side transcode: 25MB (90% decrease in size before upload)
    • Time to transcode: 60 seconds
    • onFinalized GCF ffmpeg transcode: 19MB (77% reduction in size)
    • In total a 93% reduction in size while keep high quality 720p video.

    flutter_ffmpeg is archived, the new ffmpeg flutter package is ffmpeg_kit_flutter.

    That being said, I used ffmpeg_kit_flutter to build my solution on the client side, rather than the server side, and transcode the video before uploading.

    Cons:

    1. Doubled my app size to use ffmpeg, because I needed access to both lame and x264 so I had to install the full-gpl package to gain access to these libraries.
    2. A two minute video can take up to 60 seconds to transcode.

    The pros:

    1. Low bandwidth connections will operate much better after a video is reduced in size by 90%.
    2. Large videos will transcode and ffmpegkit does not crash like other flutter packages I've tried.
    3. The second pass with ffmpeg on GCF gains another 77% reduction in size taking a video of 100's of MB's down to just 10-20 MB max for eventually delivery.
    4. Costs lower on the front and back end.

    So, you'll have to decide if the pros outweighs the cons and if 720p is high enough quality for playback. For me 720p looks perfect for video playback on a mobile phone and 1080p or higher was big time overkill.

    I've provided sample code (not full classes) to give anyone looking to implement my solution a try. It became very important, due to the amount of time to transcode, to display a progress meter so the user does not give up on the process. You'll see my simple solution to displaying transcoding progress.

    pubspec.yaml

    1 
    2 ​  ​Future&lt;​void​&gt;​ ​uploadTask​({ 
    3 ​    ​required​ ​WidgetRef​ ref, 
    4 ​    ​required​ ​File​ file, 
    5 ​    ​required​ ​String​ objectPath, 
    6 ​    ​SettableMetadata​?​ metaData, 
    7 ​    ​bool​ deleteAfterUpload ​=​ ​false​, 
    8 ​    ​bool​ displayProgressNotification ​=​ ​false​, 
    9 ​  }) ​async​ { 
    10 ​    ​String​ filePath ​=​ file.path; 
    11 ​    filename ​=​ ​basename​(file.path); 
    12  
    13 ​    ​/// Remove any instances of '//' from the path. 
    14 ​    ​final​ ​String​ path ​=​ ​'$​storagePath​/$​objectPath​'​.​replaceAll​(​'//'​, ​'/'​); 
    15 ​    ​UploadTask​ task ​=​ storage.​ref​(path).​putFile​( 
    16 ​          ​File​(filePath), 
    17 ​          metaData, 
    18 ​        ); 
    19  
    20 ​    ​/// Store UploadTask in StateNotifierProvider to monitor progress. 
    21 ​    ref.​read​(uploadingStateProvider.notifier).​myUploadTask​(task); 
    22 ​  }
    23dependencies:
    24  camera: ^0.9.4+12
    25  flutter_riverpod: ^1.0.3
    26  ffmpeg_kit_flutter_full_gpl: ^4.5.1
    27  wakelock: ^0.5.6
    28

    Riverpod StateNotifier classes to send progress updates to the ui for both transcoding and uploading to firebase storage. Assumption that users are familiar with Riverpod and StateNotifiers.

    1 
    2 ​  ​Future&lt;​void​&gt;​ ​uploadTask​({ 
    3 ​    ​required​ ​WidgetRef​ ref, 
    4 ​    ​required​ ​File​ file, 
    5 ​    ​required​ ​String​ objectPath, 
    6 ​    ​SettableMetadata​?​ metaData, 
    7 ​    ​bool​ deleteAfterUpload ​=​ ​false​, 
    8 ​    ​bool​ displayProgressNotification ​=​ ​false​, 
    9 ​  }) ​async​ { 
    10 ​    ​String​ filePath ​=​ file.path; 
    11 ​    filename ​=​ ​basename​(file.path); 
    12  
    13 ​    ​/// Remove any instances of '//' from the path. 
    14 ​    ​final​ ​String​ path ​=​ ​'$​storagePath​/$​objectPath​'​.​replaceAll​(​'//'​, ​'/'​); 
    15 ​    ​UploadTask​ task ​=​ storage.​ref​(path).​putFile​( 
    16 ​          ​File​(filePath), 
    17 ​          metaData, 
    18 ​        ); 
    19  
    20 ​    ​/// Store UploadTask in StateNotifierProvider to monitor progress. 
    21 ​    ref.​read​(uploadingStateProvider.notifier).​myUploadTask​(task); 
    22 ​  }
    23dependencies:
    24  camera: ^0.9.4+12
    25  flutter_riverpod: ^1.0.3
    26  ffmpeg_kit_flutter_full_gpl: ^4.5.1
    27  wakelock: ^0.5.6
    28@immutable
    29class TranscodeUploadMessage {
    30  const TranscodeUploadMessage({
    31    required this.id,
    32    required this.statusTitle,
    33    required this.statusMessage,
    34    required this.uploadPercentage,
    35    required this.isRunning,
    36    required this.completed,
    37    required this.showSpinner,
    38    required this.showPercentage,
    39    required this.showError,
    40  });
    41
    42  final int id;
    43  final String statusTitle;
    44  final String statusMessage;
    45  final String uploadPercentage;
    46  final bool isRunning;
    47  final bool completed;
    48  final bool showSpinner;
    49  final bool showPercentage;
    50  final bool showError;
    51
    52  TranscodeUploadMessage copyWith({
    53    int? id,
    54    String? statusTitle,
    55    String? statusMessage,
    56    String? uploadPercentage,
    57    bool? isRunning,
    58    bool? completed,
    59    bool? showSpinner,
    60    bool? showPercentage,
    61    bool? showError,
    62  }) {
    63    return TranscodeUploadMessage(
    64      id: id ?? this.id,
    65      statusTitle: statusTitle ?? this.statusTitle,
    66      statusMessage: statusMessage ?? this.statusMessage,
    67      uploadPercentage: uploadPercentage ?? this.uploadPercentage,
    68      isRunning: isRunning ?? this.isRunning,
    69      completed: completed ?? this.completed,
    70      showSpinner: showSpinner ?? this.showSpinner,
    71      showPercentage: showSpinner ?? this.showPercentage,
    72      showError: showError ?? this.showError,
    73    );
    74  }
    75}
    76
    77class TranscodeUploadMessageNotifier
    78    extends StateNotifier&lt;List&lt;TranscodeUploadMessage&gt;&gt; {
    79  TranscodeUploadMessageNotifier() : super([]);
    80
    81  /// Since our state is immutable, we are not allowed to do
    82  /// `state.add(message)`. Instead, we should create a new list of messages which
    83  /// contains the previous items and the new one.
    84  ///
    85  /// Using Dart's spread operator here is helpful!
    86  void set(TranscodeUploadMessage message) {
    87    state = [...state, message];
    88  }
    89
    90  /// Our state is immutable. So we're making a new list instead of changing
    91  /// the existing list.
    92  void remove(int id) {
    93    state = [
    94      for (final message in state)
    95        if (message.id != id) message,
    96    ];
    97  }
    98
    99  /// Update message. Since our state is immutable, we need to make a copy of
    100  /// the message. We're using our `copyWith` method implemented before to help
    101  /// with that.
    102  void update(TranscodeUploadMessage messageUpdated) {
    103    state = [
    104      for (final message in state)
    105        if (message.id == messageUpdated.id)
    106
    107          /// Use copyWith to update a message
    108          message.copyWith(
    109            statusTitle: messageUpdated.statusTitle,
    110            statusMessage: messageUpdated.statusMessage,
    111            uploadPercentage: messageUpdated.uploadPercentage,
    112            isRunning: messageUpdated.isRunning,
    113            completed: messageUpdated.completed,
    114            showSpinner: messageUpdated.showSpinner,
    115            showPercentage: messageUpdated.showPercentage,
    116            showError: messageUpdated.showError,
    117          )
    118        else
    119
    120          /// other messages, which there are not any at this time, are not
    121          /// modified
    122          message,
    123    ];
    124  }
    125}
    126
    127/// Using StateNotifierProvider to allow the UI to interact with our
    128/// TranscodeUploadMessageNotifier class.
    129final transcodeMessageProvider = StateNotifierProvider.autoDispose&lt;
    130    TranscodeUploadMessageNotifier, List&lt;TranscodeUploadMessage&gt;&gt;((ref) {
    131  return TranscodeUploadMessageNotifier();
    132});
    133

    ffmpegkit package running ffmpeg commands and sending transcoding statistics to the StateNotifier. (Missing quite a bit of code, but pseudocode to demonstrate.)

    1 
    2 ​  ​Future&lt;​void​&gt;​ ​uploadTask​({ 
    3 ​    ​required​ ​WidgetRef​ ref, 
    4 ​    ​required​ ​File​ file, 
    5 ​    ​required​ ​String​ objectPath, 
    6 ​    ​SettableMetadata​?​ metaData, 
    7 ​    ​bool​ deleteAfterUpload ​=​ ​false​, 
    8 ​    ​bool​ displayProgressNotification ​=​ ​false​, 
    9 ​  }) ​async​ { 
    10 ​    ​String​ filePath ​=​ file.path; 
    11 ​    filename ​=​ ​basename​(file.path); 
    12  
    13 ​    ​/// Remove any instances of '//' from the path. 
    14 ​    ​final​ ​String​ path ​=​ ​'$​storagePath​/$​objectPath​'​.​replaceAll​(​'//'​, ​'/'​); 
    15 ​    ​UploadTask​ task ​=​ storage.​ref​(path).​putFile​( 
    16 ​          ​File​(filePath), 
    17 ​          metaData, 
    18 ​        ); 
    19  
    20 ​    ​/// Store UploadTask in StateNotifierProvider to monitor progress. 
    21 ​    ref.​read​(uploadingStateProvider.notifier).​myUploadTask​(task); 
    22 ​  }
    23dependencies:
    24  camera: ^0.9.4+12
    25  flutter_riverpod: ^1.0.3
    26  ffmpeg_kit_flutter_full_gpl: ^4.5.1
    27  wakelock: ^0.5.6
    28@immutable
    29class TranscodeUploadMessage {
    30  const TranscodeUploadMessage({
    31    required this.id,
    32    required this.statusTitle,
    33    required this.statusMessage,
    34    required this.uploadPercentage,
    35    required this.isRunning,
    36    required this.completed,
    37    required this.showSpinner,
    38    required this.showPercentage,
    39    required this.showError,
    40  });
    41
    42  final int id;
    43  final String statusTitle;
    44  final String statusMessage;
    45  final String uploadPercentage;
    46  final bool isRunning;
    47  final bool completed;
    48  final bool showSpinner;
    49  final bool showPercentage;
    50  final bool showError;
    51
    52  TranscodeUploadMessage copyWith({
    53    int? id,
    54    String? statusTitle,
    55    String? statusMessage,
    56    String? uploadPercentage,
    57    bool? isRunning,
    58    bool? completed,
    59    bool? showSpinner,
    60    bool? showPercentage,
    61    bool? showError,
    62  }) {
    63    return TranscodeUploadMessage(
    64      id: id ?? this.id,
    65      statusTitle: statusTitle ?? this.statusTitle,
    66      statusMessage: statusMessage ?? this.statusMessage,
    67      uploadPercentage: uploadPercentage ?? this.uploadPercentage,
    68      isRunning: isRunning ?? this.isRunning,
    69      completed: completed ?? this.completed,
    70      showSpinner: showSpinner ?? this.showSpinner,
    71      showPercentage: showSpinner ?? this.showPercentage,
    72      showError: showError ?? this.showError,
    73    );
    74  }
    75}
    76
    77class TranscodeUploadMessageNotifier
    78    extends StateNotifier&lt;List&lt;TranscodeUploadMessage&gt;&gt; {
    79  TranscodeUploadMessageNotifier() : super([]);
    80
    81  /// Since our state is immutable, we are not allowed to do
    82  /// `state.add(message)`. Instead, we should create a new list of messages which
    83  /// contains the previous items and the new one.
    84  ///
    85  /// Using Dart's spread operator here is helpful!
    86  void set(TranscodeUploadMessage message) {
    87    state = [...state, message];
    88  }
    89
    90  /// Our state is immutable. So we're making a new list instead of changing
    91  /// the existing list.
    92  void remove(int id) {
    93    state = [
    94      for (final message in state)
    95        if (message.id != id) message,
    96    ];
    97  }
    98
    99  /// Update message. Since our state is immutable, we need to make a copy of
    100  /// the message. We're using our `copyWith` method implemented before to help
    101  /// with that.
    102  void update(TranscodeUploadMessage messageUpdated) {
    103    state = [
    104      for (final message in state)
    105        if (message.id == messageUpdated.id)
    106
    107          /// Use copyWith to update a message
    108          message.copyWith(
    109            statusTitle: messageUpdated.statusTitle,
    110            statusMessage: messageUpdated.statusMessage,
    111            uploadPercentage: messageUpdated.uploadPercentage,
    112            isRunning: messageUpdated.isRunning,
    113            completed: messageUpdated.completed,
    114            showSpinner: messageUpdated.showSpinner,
    115            showPercentage: messageUpdated.showPercentage,
    116            showError: messageUpdated.showError,
    117          )
    118        else
    119
    120          /// other messages, which there are not any at this time, are not
    121          /// modified
    122          message,
    123    ];
    124  }
    125}
    126
    127/// Using StateNotifierProvider to allow the UI to interact with our
    128/// TranscodeUploadMessageNotifier class.
    129final transcodeMessageProvider = StateNotifierProvider.autoDispose&lt;
    130    TranscodeUploadMessageNotifier, List&lt;TranscodeUploadMessage&gt;&gt;((ref) {
    131  return TranscodeUploadMessageNotifier();
    132});
    133/// By default, set to video ffmpeg command.
    134String ffmpegCommand = '-i $messageUri '
    135    '-acodec aac '
    136    '-vcodec libx264 '
    137    '-f mp4 -preset veryfast '
    138    '-movflags frag_keyframe+empty_moov '
    139    '-crf 23 $newMessageUri';
    140
    141if (_recordingType == RecordingType.audio) {
    142  ffmpegCommand = '-vn '
    143      '-i $messageUri '
    144      '-y '
    145      '-acodec libmp3lame '
    146      '-f '
    147      'mp3 '
    148      '$newMessageUri';
    149}
    150
    151/// Set the initial state notifier as we start transcoding.
    152ref
    153.read(transcodeMessageProvider.notifier)
    154.set(const TranscodeUploadMessage(
    155  id: 1,
    156  statusTitle: 'Transcoding Recording',
    157  statusMessage: 'Your recording is being transcoded '
    158      'before upload. Please do not navigate away from this screen.',
    159  uploadPercentage: '0%',
    160  isRunning: true,
    161  completed: false,
    162  showSpinner: false,
    163  showPercentage: false,
    164  showError: false,
    165));
    166
    167await FFmpegKit.executeAsync(
    168  ffmpegCommand,
    169  (Session session) async {
    170    final ReturnCode? returnCode = await session.getReturnCode();
    171
    172    if (ReturnCode.isSuccess(returnCode)) {
    173      /// Transcoding is complete, now display uploading message
    174      /// and spinner at 0%.
    175      ref
    176          .read(transcodeMessageProvider.notifier)
    177          .update(const TranscodeUploadMessage(
    178            id: 1,
    179            statusTitle: 'Uploading Recording',
    180            statusMessage:
    181                'Your recording is now being '
    182                'uploaded. Please do not navigate away from this screen.',
    183            uploadPercentage: '0%',
    184            isRunning: true,
    185            completed: false,
    186            showSpinner: true,
    187            showPercentage: true,
    188            showError: false,
    189          ));
    190
    191      /// Upload the now transcoded video/audio to cloud storage where
    192      /// Use flutterfire firebase storage tasks to get upload
    193      /// progress. Your firebase storage function can also 
    194      /// reuse the transcodeMessageProvider to send UI state
    195      /// updates for the upload, which will happen very quickly
    196      /// even on slow connections now that the recording size
    197      /// is dramatically reduced.
    198      await uploadRecordingToFirebaseCloudStorage(ref);
    199    } else if (ReturnCode.isCancel(returnCode)) {
    200      // Do something if canceled
    201    } else {
    202      // Do something with the error
    203    }
    204  },
    205  (Log log) =&gt; debugPrint(log.getMessage()),
    206  (Statistics statistic) {
    207    /// Statistics provides a running transcoding progress meter.
    208    int completePercentage = (statistic.getTime() * 100) ~/ _duration!;
    209    ref
    210        .read(transcodeMessageProvider.notifier)
    211        .update(TranscodeUploadMessage(
    212          id: 1,
    213          statusTitle: 'Transcoding Recording',
    214          statusMessage: 'Your recording is being '
    215              'transcoded. Please do not navigate away from this screen.',
    216          uploadPercentage: '$completePercentage%',
    217          isRunning: true,
    218          completed: false,
    219          showSpinner: true,
    220          showPercentage: true,
    221          showError: false,
    222        ));
    223  }).then((Session session) {
    224debugPrint(
    225    'Async FFmpeg process started with sessionId ${session.getSessionId()}.');
    226}).catchError((error) async {
    227debugPrint('transcoding error: $error');
    228});
    229

    Use a Riverpod Consumer to update UI by watching the StateNotifier and displaying updated state in your UI.

    1 
    2 ​  ​Future&lt;​void​&gt;​ ​uploadTask​({ 
    3 ​    ​required​ ​WidgetRef​ ref, 
    4 ​    ​required​ ​File​ file, 
    5 ​    ​required​ ​String​ objectPath, 
    6 ​    ​SettableMetadata​?​ metaData, 
    7 ​    ​bool​ deleteAfterUpload ​=​ ​false​, 
    8 ​    ​bool​ displayProgressNotification ​=​ ​false​, 
    9 ​  }) ​async​ { 
    10 ​    ​String​ filePath ​=​ file.path; 
    11 ​    filename ​=​ ​basename​(file.path); 
    12  
    13 ​    ​/// Remove any instances of '//' from the path. 
    14 ​    ​final​ ​String​ path ​=​ ​'$​storagePath​/$​objectPath​'​.​replaceAll​(​'//'​, ​'/'​); 
    15 ​    ​UploadTask​ task ​=​ storage.​ref​(path).​putFile​( 
    16 ​          ​File​(filePath), 
    17 ​          metaData, 
    18 ​        ); 
    19  
    20 ​    ​/// Store UploadTask in StateNotifierProvider to monitor progress. 
    21 ​    ref.​read​(uploadingStateProvider.notifier).​myUploadTask​(task); 
    22 ​  }
    23dependencies:
    24  camera: ^0.9.4+12
    25  flutter_riverpod: ^1.0.3
    26  ffmpeg_kit_flutter_full_gpl: ^4.5.1
    27  wakelock: ^0.5.6
    28@immutable
    29class TranscodeUploadMessage {
    30  const TranscodeUploadMessage({
    31    required this.id,
    32    required this.statusTitle,
    33    required this.statusMessage,
    34    required this.uploadPercentage,
    35    required this.isRunning,
    36    required this.completed,
    37    required this.showSpinner,
    38    required this.showPercentage,
    39    required this.showError,
    40  });
    41
    42  final int id;
    43  final String statusTitle;
    44  final String statusMessage;
    45  final String uploadPercentage;
    46  final bool isRunning;
    47  final bool completed;
    48  final bool showSpinner;
    49  final bool showPercentage;
    50  final bool showError;
    51
    52  TranscodeUploadMessage copyWith({
    53    int? id,
    54    String? statusTitle,
    55    String? statusMessage,
    56    String? uploadPercentage,
    57    bool? isRunning,
    58    bool? completed,
    59    bool? showSpinner,
    60    bool? showPercentage,
    61    bool? showError,
    62  }) {
    63    return TranscodeUploadMessage(
    64      id: id ?? this.id,
    65      statusTitle: statusTitle ?? this.statusTitle,
    66      statusMessage: statusMessage ?? this.statusMessage,
    67      uploadPercentage: uploadPercentage ?? this.uploadPercentage,
    68      isRunning: isRunning ?? this.isRunning,
    69      completed: completed ?? this.completed,
    70      showSpinner: showSpinner ?? this.showSpinner,
    71      showPercentage: showSpinner ?? this.showPercentage,
    72      showError: showError ?? this.showError,
    73    );
    74  }
    75}
    76
    77class TranscodeUploadMessageNotifier
    78    extends StateNotifier&lt;List&lt;TranscodeUploadMessage&gt;&gt; {
    79  TranscodeUploadMessageNotifier() : super([]);
    80
    81  /// Since our state is immutable, we are not allowed to do
    82  /// `state.add(message)`. Instead, we should create a new list of messages which
    83  /// contains the previous items and the new one.
    84  ///
    85  /// Using Dart's spread operator here is helpful!
    86  void set(TranscodeUploadMessage message) {
    87    state = [...state, message];
    88  }
    89
    90  /// Our state is immutable. So we're making a new list instead of changing
    91  /// the existing list.
    92  void remove(int id) {
    93    state = [
    94      for (final message in state)
    95        if (message.id != id) message,
    96    ];
    97  }
    98
    99  /// Update message. Since our state is immutable, we need to make a copy of
    100  /// the message. We're using our `copyWith` method implemented before to help
    101  /// with that.
    102  void update(TranscodeUploadMessage messageUpdated) {
    103    state = [
    104      for (final message in state)
    105        if (message.id == messageUpdated.id)
    106
    107          /// Use copyWith to update a message
    108          message.copyWith(
    109            statusTitle: messageUpdated.statusTitle,
    110            statusMessage: messageUpdated.statusMessage,
    111            uploadPercentage: messageUpdated.uploadPercentage,
    112            isRunning: messageUpdated.isRunning,
    113            completed: messageUpdated.completed,
    114            showSpinner: messageUpdated.showSpinner,
    115            showPercentage: messageUpdated.showPercentage,
    116            showError: messageUpdated.showError,
    117          )
    118        else
    119
    120          /// other messages, which there are not any at this time, are not
    121          /// modified
    122          message,
    123    ];
    124  }
    125}
    126
    127/// Using StateNotifierProvider to allow the UI to interact with our
    128/// TranscodeUploadMessageNotifier class.
    129final transcodeMessageProvider = StateNotifierProvider.autoDispose&lt;
    130    TranscodeUploadMessageNotifier, List&lt;TranscodeUploadMessage&gt;&gt;((ref) {
    131  return TranscodeUploadMessageNotifier();
    132});
    133/// By default, set to video ffmpeg command.
    134String ffmpegCommand = '-i $messageUri '
    135    '-acodec aac '
    136    '-vcodec libx264 '
    137    '-f mp4 -preset veryfast '
    138    '-movflags frag_keyframe+empty_moov '
    139    '-crf 23 $newMessageUri';
    140
    141if (_recordingType == RecordingType.audio) {
    142  ffmpegCommand = '-vn '
    143      '-i $messageUri '
    144      '-y '
    145      '-acodec libmp3lame '
    146      '-f '
    147      'mp3 '
    148      '$newMessageUri';
    149}
    150
    151/// Set the initial state notifier as we start transcoding.
    152ref
    153.read(transcodeMessageProvider.notifier)
    154.set(const TranscodeUploadMessage(
    155  id: 1,
    156  statusTitle: 'Transcoding Recording',
    157  statusMessage: 'Your recording is being transcoded '
    158      'before upload. Please do not navigate away from this screen.',
    159  uploadPercentage: '0%',
    160  isRunning: true,
    161  completed: false,
    162  showSpinner: false,
    163  showPercentage: false,
    164  showError: false,
    165));
    166
    167await FFmpegKit.executeAsync(
    168  ffmpegCommand,
    169  (Session session) async {
    170    final ReturnCode? returnCode = await session.getReturnCode();
    171
    172    if (ReturnCode.isSuccess(returnCode)) {
    173      /// Transcoding is complete, now display uploading message
    174      /// and spinner at 0%.
    175      ref
    176          .read(transcodeMessageProvider.notifier)
    177          .update(const TranscodeUploadMessage(
    178            id: 1,
    179            statusTitle: 'Uploading Recording',
    180            statusMessage:
    181                'Your recording is now being '
    182                'uploaded. Please do not navigate away from this screen.',
    183            uploadPercentage: '0%',
    184            isRunning: true,
    185            completed: false,
    186            showSpinner: true,
    187            showPercentage: true,
    188            showError: false,
    189          ));
    190
    191      /// Upload the now transcoded video/audio to cloud storage where
    192      /// Use flutterfire firebase storage tasks to get upload
    193      /// progress. Your firebase storage function can also 
    194      /// reuse the transcodeMessageProvider to send UI state
    195      /// updates for the upload, which will happen very quickly
    196      /// even on slow connections now that the recording size
    197      /// is dramatically reduced.
    198      await uploadRecordingToFirebaseCloudStorage(ref);
    199    } else if (ReturnCode.isCancel(returnCode)) {
    200      // Do something if canceled
    201    } else {
    202      // Do something with the error
    203    }
    204  },
    205  (Log log) =&gt; debugPrint(log.getMessage()),
    206  (Statistics statistic) {
    207    /// Statistics provides a running transcoding progress meter.
    208    int completePercentage = (statistic.getTime() * 100) ~/ _duration!;
    209    ref
    210        .read(transcodeMessageProvider.notifier)
    211        .update(TranscodeUploadMessage(
    212          id: 1,
    213          statusTitle: 'Transcoding Recording',
    214          statusMessage: 'Your recording is being '
    215              'transcoded. Please do not navigate away from this screen.',
    216          uploadPercentage: '$completePercentage%',
    217          isRunning: true,
    218          completed: false,
    219          showSpinner: true,
    220          showPercentage: true,
    221          showError: false,
    222        ));
    223  }).then((Session session) {
    224debugPrint(
    225    'Async FFmpeg process started with sessionId ${session.getSessionId()}.');
    226}).catchError((error) async {
    227debugPrint('transcoding error: $error');
    228});
    229Consumer(
    230    builder: (context, watch, child) {
    231      final List&lt;TranscodeUploadMessage&gt; messages =
    232          ref.watch(transcodeMessageProvider);
    233      if (messages.isEmpty) {
    234        return const SizedBox.shrink();
    235      }
    236
    237      final message = messages[0];
    238
    239      if (message.isRunning ||
    240          message.completed ||
    241          message.showError) {
    242        // Display widgets with StateNotifier data
    243      }
    244
    245      return const SizedBox.shrink();
    246    },
    247)
    248

    Source https://stackoverflow.com/questions/71027684

    Community Discussions contain sources that include Stack Exchange Network

    Tutorials and Learning Resources in Wifi

    Tutorials and Learning Resources are not available at this moment for Wifi

    Share this Page

    share link

    Get latest updates on Wifi