Unofficial.Owlet
0.1.4
dotnet add package Unofficial.Owlet --version 0.1.4
NuGet\Install-Package Unofficial.Owlet -Version 0.1.4
<PackageReference Include="Unofficial.Owlet" Version="0.1.4" />
paket add Unofficial.Owlet --version 0.1.4
#r "nuget: Unofficial.Owlet, 0.1.4"
// Install Unofficial.Owlet as a Cake Addin #addin nuget:?package=Unofficial.Owlet&version=0.1.4 // Install Unofficial.Owlet as a Cake Tool #tool nuget:?package=Unofficial.Owlet&version=0.1.4
Owlet Smart Sock API for .NET
Unofficial .NET Standard 2.0 Library. Run on Linux, Mac, Windows.
Notice
This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by Owlet Baby Care or any of its affiliates or subsidiaries. This is an independent and unofficial API. Use at your own risk.
Example Data
Device Properties for specific Owlet Smart Sock:
[
{
"Name": "BATT_LEVEL",
"Value": 93,
"DataUpdatedAt": "2018-01-01T12:34:56Z"
// ...
},
{
"Name": "HEART_RATE",
"Value": 125,
"DataUpdatedAt": "2018-01-01T12:34:56Z"
// ...
},
{
"Name": "OXYGEN_LEVEL",
"Value": 99,
"DataUpdatedAt": "2018-01-01T12:34:56Z"
// ...
}
// ...
]
Using this Owlet API Wrapper
Install NuGet package
dotnet add package Unofficial.Owlet
Using .NET Core Dependency Injection
// ...
using Unofficial.Owlet.Extensions;
// ...
private void ConfigureServices(IServiceCollection services)
{
// ...
services.AddOwletApi();
// ...
}
Then, you can import the specific API services you would like to consume into your class:
namespace My.App
{
public class MyClass
{
private readonly IOwletUserApi _owletUserApi;
private readonly IOwletDeviceApi _owletDeviceApi;
public MyClass(IOwletUserApi owletUserApi, IOwletDeviceApi owletDeviceApi)
{
this._owletUserApi = owletUserApi;
this._owletDeviceApi = owletDeviceApi;
}
public async Task Run()
{
var email = ""; // from IOptions<YourConfigClass> or input
var password = ""; // from IOptions<YourConfigClass> or input
await Login(email, password);
var mySock = await GetDeviceSerialNumber(); // get first sock in your account
var mySockProperties = await GetDeviceProperties(mySock.Device.DeviceSerialNumber);
foreach (var property in mySockProperties)
{
Console.WriteLine($"{property.Property.Name} : {property.Property.Value} ({property.Property.DataUpdatedAt?.ToString("MM/dd/yyyy HH:mm")})");
}
}
public async Task<OwletSignInResponse> Login(string email, string password)
{
return await this._owletUserApi.LoginAsync(email, password);
}
public async Task<string> GetDeviceSerialNumber()
{
return await this._owletDeviceApi.GetDevicesAsync()
.First()?.Device?.DeviceSerialNumber;
}
public async Task<IEnumerable<OwletDevicePropertyResponse>> GetDeviceProperties(string deviceSerialNumber)
{
return await this._owletDeviceApi.TryGetFreshDevicePropertiesAsync(deviceSerialNumber);
}
}
}
Setting Up Dependency Injection with User Settings
You may want to configure your account email/password in your startup method, then forget about it later. Or you may want to always use your current sock's device serial number (if you know it - or find it using this library), so that you can reduce an additional API call to speed up retrieval of your Owlet Smart Sock data.
using Unofficial.Owlet.Extensions;
using Unofficial.Owlet.Models;
// ...
private void ConfigureServices(IServiceCollection services)
{
services.AddOwletApi(options =>
{
options.WithSettings(new OwletApiSettings
{
Email = "abc@abc.com",
Password = "mypassword",
KnownDeviceSerialNumbers = new [] { "A...." }
});
});
// ...
}
Then, if no accessToken
is provided to some of the API methods, it will check for this configuration value and log you in as needed automatically. No more calls to LoginAsync(email, password)
!
namespace My.App
{
public class MyClass
{
// ...
public async Task Run()
{
// no need to make explicit LoginAsync() call!
// this Owlet API library will try for you!
var mySock = await GetDeviceSerialNumber(); // get first sock in your account
var mySockProperties = await GetDeviceProperties(mySock.Device.DeviceSerialNumber);
foreach (var property in mySockProperties)
{
Console.WriteLine($"{property.Property.Name} : {property.Property.Value} ({property.Property.DataUpdatedAt?.ToString("MM/dd/yyyy HH:mm")})");
}
}
// ...
}
}
Managing User Secrets
This is not required to consume this library, but a note nonetheless.
If you use the IOptions<T>
pattern to read configuration from appsettings.json
, you may want to consider storing your Email/Password in a secrets.json
file stored on your client machine outside of this (or your own) code repository - which can accidentally leak to the public!
# recommend .NET Core 2.1+ SDK
dotnet tool install -g dotnet-user-secrets
cd $ProjectRoot
cd src/Unofficial.Owlet.TestConsole/
dotnet-user-secrets list
dotnet-user-secrets set owlet:email abc@abc.com
dotnet-user-secrets set owlet:password mypassword
How Does It Work?
I touched on this briefly above, but it's worth calling out again.
Other collaborators have identified that it's easy enough to request device properties from the Ayla Networks IoT platform, but the data ends up getting stale after ~30 seconds
, or after the Owlet app has closed.
As it turns out, there's a property returned named APP_ACTIVE
that reads as 1
when the mobile application is in-use, and 0
when not.
If we want to fake that the app is always open so that we can collect data over a time period, we need to continually write a new APP_ACTIVE
datapoint with value of 1
such that the Owlet base station will broadcast the other assorted sock datapoints. Of course, there is a time delay between the initial mark of APP_ACTIVE
to when the base station is able to create new datapoint records. So, this library takes a swing at 2 seconds
... even though realistically, that's likely not sufficient for most experiences (2 seconds between notifying Owlet API that it's active, having data requested from the base station, and the base station replying with datapoints).
I mentioned the risks above earlier, too. You can see that this library is making the assumption that there is a property named APP_ACTIVE
and that its value needs to be 1
in order for data to update. If this property ever gets renamed, or the value it needs to be is ever updated, or an alternate mechanism is introduced, this library will need to be updated for that.
Data Flow
- Login (
/users/sign_in
) - Get Devices for Account (
/apiv1/devices
) - Get Device Properties (
/apiv1/dsns/{deviceSerialNumber}/properties
)- Are properties stale?
- Create new datapoint marking app as "active" (
/apiv1/properties/{propertyId}/datapoints
) - Wait a few seconds for data to propagate
- Query for Device Properties again (repeat)
- Create new datapoint marking app as "active" (
- Are properties stale?
2018 Mitchell Barry
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.DependencyInjection (>= 2.1.1)
- Microsoft.Extensions.Http (>= 2.1.1)
- Microsoft.Extensions.Http.Polly (>= 2.1.1)
- Newtonsoft.Json (>= 11.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.1.4 | 1,043 | 7/8/2018 |
0.1.4-CI-20180722-132452 | 678 | 7/23/2018 |
0.1.4-CI-20180708-114345 | 781 | 7/8/2018 |
0.1.3 | 908 | 7/8/2018 |
0.1.3-CI-20180708-112047 | 784 | 7/8/2018 |
0.1.2 | 940 | 7/8/2018 |
0.1.2-CI-20180708-104426 | 785 | 7/8/2018 |
0.1.1-CI-20180708-101247 | 761 | 7/8/2018 |
0.1.0-CI-20180708-083220 | 769 | 7/8/2018 |