Skip to content

Commit

Permalink
Merge pull request #32 from wildlifeai/improvements
Browse files Browse the repository at this point in the history
Various bugfixes and improvements
  • Loading branch information
Burzo authored Apr 2, 2024
2 parents 286772b + bb6de0c commit 2a7b9dc
Show file tree
Hide file tree
Showing 14 changed files with 555 additions and 195 deletions.
10 changes: 10 additions & 0 deletions ios/WildlifeWatcher.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,13 @@
PRODUCT_BUNDLE_IDENTIFIER = com.wildlife.wildlifewatcher;
PRODUCT_NAME = WildlifeWatcher;
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
Expand Down Expand Up @@ -347,7 +352,12 @@
PRODUCT_NAME = WildlifeWatcher;
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Wildlife Watcher App Store";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
Expand Down
6 changes: 6 additions & 0 deletions ios/WildlifeWatcher/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,17 @@
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string></string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
Expand Down
61 changes: 59 additions & 2 deletions src/ble/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export const COMMANDS: {
[CommandNames.ID]: {
name: CommandNames.ID,
readCommand: "id",
readRegex: /\bDevEui:\s*([0-9A-Fa-f:]+)\b/,
},
[CommandNames.VERSION]: {
name: CommandNames.VERSION,
Expand All @@ -77,7 +76,7 @@ export const COMMANDS: {
[CommandNames.BATTERY]: {
name: CommandNames.BATTERY,
readCommand: "battery",
readRegex: /\bBattery\s=\s([0-9.]+V)\b/,
readRegex: /\bBattery\s=\s(100|\d{1,3})%/,
},
[CommandNames.SENSOR]: {
name: CommandNames.SENSOR,
Expand Down Expand Up @@ -146,3 +145,61 @@ export const COMMANDS: {
readRegex: /(Device will enter DFU mode after disconnecting.)\s*/,
},
}

type CharacteristicProperty =
| "Read"
| "Write"
| "WriteWithoutResponse"
| "Notify"

type CharacteristicProperties = {
[key in CharacteristicProperty]?: CharacteristicProperty
}

type Descriptor = {
value: any
uuid: string
}

type Characteristic = {
properties: CharacteristicProperties
characteristic: string
service: string
descriptors?: Descriptor[]
}

type Service = {
uuid: string
}

type ManufacturerRawData = {
bytes: number[]
data: string
CDVType: string
}

type RawData = {
bytes: number[]
data: string
CDVType: string
}

type Advertising = {
manufacturerData: any
txPowerLevel: number
isConnectable: boolean
serviceData: any
localName: string
serviceUUIDs: string[]
manufacturerRawData: ManufacturerRawData
rawData: RawData
}

export type Services = {
characteristics: Characteristic[]
services: Service[]
advertising: Advertising
name: string
rssi: number
id: string
}
7 changes: 5 additions & 2 deletions src/components/AppDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const useAppDrawer = () => useContext(DrawerContext)

export const AppDrawer = ({ children }: PropsWithChildren<unknown>) => {
const [isOpen, setIsOpen] = useState(false)
const { padding, spacing } = useExtendedTheme()
const { appPadding, spacing } = useExtendedTheme()
const { setIsLoggedIn, isLoggedIn } = useAuth()
const { top } = useSafeAreaInsets()

Expand All @@ -43,7 +43,10 @@ export const AppDrawer = ({ children }: PropsWithChildren<unknown>) => {
renderDrawerContent={() => {
return (
<Surface
style={[{ padding, paddingTop: padding + top }, styles.view]}
style={[
{ padding: appPadding, paddingTop: appPadding + top },
styles.view,
]}
>
<Avatar.Image source={require("../assets/avatar.png")} />
<WWText variant="bodyLarge">I'm empty at the moment.</WWText>
Expand Down
6 changes: 4 additions & 2 deletions src/components/CustomKeyboardAvoidingView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from "react-native"

import { useSafeAreaInsets } from "react-native-safe-area-context"
import { useExtendedTheme } from "../theme"

type Props = {
style?: StyleProp<ViewStyle>
Expand All @@ -22,10 +23,11 @@ export const CustomKeyboardAvoidingView = ({
}: PropsWithChildren<Props>) => {
const insets = useSafeAreaInsets()
const [bottomPadding, setBottomPadding] = useState(insets.bottom)
const { spacing } = useExtendedTheme()

useEffect(() => {
setBottomPadding(insets.bottom)
}, [insets.bottom, insets.top])
setBottomPadding(insets.bottom + spacing)
}, [insets.bottom, insets.top, spacing])

return (
<KeyboardAvoidingView
Expand Down
10 changes: 3 additions & 7 deletions src/components/ui/WWScreenView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@ export const WWScreenView = ({
children,
...props
}: PropsWithChildren<SafeAreaViewProps>) => {
const { padding } = useExtendedTheme()
const { appPadding } = useExtendedTheme()

return (
<TouchableWithoutFeedback
style={styles.view}
onPress={Keyboard.dismiss}
accessible={false}
>
<SafeAreaView style={[{ padding }, styles.view, props.style]}>
<TouchableWithoutFeedback style={styles.view} onPress={Keyboard.dismiss}>
<SafeAreaView style={[{ padding: appPadding }, styles.view, props.style]}>
{children}
</SafeAreaView>
</TouchableWithoutFeedback>
Expand Down
31 changes: 31 additions & 0 deletions src/components/ui/WWScrollView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { forwardRef } from "react"
import {
ScrollViewProps,
StyleProp,
StyleSheet,
View,
ViewStyle,
} from "react-native"
import { ScrollView } from "react-native-gesture-handler"

type Props = ScrollViewProps & {
containerStyle?: StyleProp<ViewStyle>
}

export const WWScrollView = forwardRef<ScrollView, Props>(
({ children, containerStyle, ...props }, ref) => {
return (
<ScrollView ref={ref} {...props} style={[styles.view, props.style]}>
<View onStartShouldSetResponder={() => true} style={containerStyle}>
{children}
</View>
</ScrollView>
)
},
)

const styles = StyleSheet.create({
view: {
flex: 1,
},
})
34 changes: 21 additions & 13 deletions src/hooks/useBle.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React, { useCallback, useEffect, useRef } from "react"
import React, { useCallback, useEffect, useRef, useState } from "react"

import { Platform } from "react-native"

import BleManager from "react-native-ble-manager"
import { Peripheral } from "react-native-ble-manager"

import { BLE_SERVICE_UUID } from "../utils/constants"
import {
BLE_CHARACTERISTIC_READ_UUID,
BLE_SERVICE_UUID,
} from "../utils/constants"
import { invokeWithTimeout, sleep } from "../utils/helpers"
extractServiceAndCharacteristic,
invokeWithTimeout,
sleep,
} from "../utils/helpers"
import { guard, log, logError } from "../utils/logger"
import { useAppDispatch, useAppSelector } from "../redux"
import {
Expand All @@ -30,6 +31,7 @@ import {
CommandConstructOptions,
CommandControlTypes,
CommandNames,
Services,
} from "../ble/types"
import { constructCommandString } from "../ble/parser"

Expand Down Expand Up @@ -73,6 +75,8 @@ const PING_REQUEST: string[] = []
export const useBle = (): ReturnType => {
const { initialized } = useAppSelector((state) => state.bleLibrary)

const [isBleConnecting, setIsBleConnecting] = useState(false)

const devices = useAppSelector((state) => state.devices)
const scanning = useAppSelector((state) => state.scanning)

Expand Down Expand Up @@ -232,9 +236,7 @@ export const useBle = (): ReturnType => {
)

const isDeviceReconnecting = useRef<{ [x: string]: boolean }>({})
const isBleConnecting = Object.values(isDeviceReconnecting.current).find(
(isConnected) => isConnected,
)

const connectDevice = useCallback(
async (peripheral: ExtendedPeripheral, timeout?: number) => {
if (!initialized || peripheral.loading) return peripheral
Expand All @@ -261,6 +263,8 @@ export const useBle = (): ReturnType => {

isDeviceReconnecting.current[peripheral.id] = true

setIsBleConnecting(true)

const newPeripheral = { ...peripheral }

dispatch(deviceLoading({ id: newPeripheral.id, loading: true }))
Expand All @@ -286,18 +290,22 @@ export const useBle = (): ReturnType => {

log(`Device ${deviceIdentification} connected`)

await invokeWithTimeout(
const services = (await invokeWithTimeout(
() => BleManager.retrieveServices(newPeripheral.id),
"BleManager.retrieveServices",
timeout,
)
)) as Services

log(`Device ${deviceIdentification} services retireved`)

const extractedServices = extractServiceAndCharacteristic(services)

newPeripheral.services = extractedServices

await BleManager.startNotification(
newPeripheral.id,
BLE_SERVICE_UUID,
BLE_CHARACTERISTIC_READ_UUID,
extractedServices.serviceCharacteristic,
extractedServices.readCharacteristic,
)

log(`Device ${deviceIdentification} notifications started`)
Expand All @@ -313,7 +321,6 @@ export const useBle = (): ReturnType => {
await ping()

newPeripheral.connected = true

newPeripheral.intervals = {
ping: setInterval(async () => await ping(), 20000),
}
Expand All @@ -329,6 +336,7 @@ export const useBle = (): ReturnType => {
dispatch(deviceLoading({ id: newPeripheral.id, loading: false }))

if (isDeviceReconnecting.current[peripheral.id]) {
setIsBleConnecting(false)
isDeviceReconnecting.current[peripheral.id] = false
}

Expand Down
1 change: 0 additions & 1 deletion src/hooks/useBleListeners.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ export const useBleListeners = () => {
console.debug(JSON.stringify(text))

const currentConfiguration = configRef.current[peripheral] || {}
// const currentPeripheral = devicesRef.current[peripheral]
const currentLog = allLogs.current[peripheral] || ""

if (allLogs.current[peripheral]) {
Expand Down
14 changes: 13 additions & 1 deletion src/hooks/useCommand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ const TIMEOUT = 1000 * 10
export const useCommand = ({ deviceId, command }: Props) => {
const requestRef = useRef<NodeJS.Timeout>()
const timeoutRef = useRef<NodeJS.Timeout>()

const [goal, setGoal] = useState<number | string>()
const [commandLoading, setCommandLoading] = useState(true)

const { write } = useBleActions()
const devices = useAppSelector((state) => state.devices)
Expand Down Expand Up @@ -71,6 +73,7 @@ export const useCommand = ({ deviceId, command }: Props) => {
const set = useCallback(
(data?: string) => {
clearTimers()
setCommandLoading(true)

sendCommand(CommandControlTypes.WRITE, data)

Expand All @@ -86,6 +89,8 @@ export const useCommand = ({ deviceId, command }: Props) => {
clearInterval(requestRef.current)
}

setCommandLoading(false)

dispatch(
deviceConfigChanged({
id: deviceId,
Expand Down Expand Up @@ -122,6 +127,8 @@ export const useCommand = ({ deviceId, command }: Props) => {
// Means its a set only command in reality
if (!command.readCommand) return

setCommandLoading(true)

sendCommand(CommandControlTypes.READ)

requestRef.current = setInterval(
Expand All @@ -133,6 +140,8 @@ export const useCommand = ({ deviceId, command }: Props) => {
clearInterval(requestRef.current)
}

setCommandLoading(false)

dispatch(
deviceConfigChanged({
id: deviceId,
Expand Down Expand Up @@ -170,7 +179,7 @@ export const useCommand = ({ deviceId, command }: Props) => {
})
) {
clearTimers()

setCommandLoading(false)
/**
* If the hook already detects the correct configuration
* when it first renders, the get() method isn't even
Expand Down Expand Up @@ -209,6 +218,7 @@ export const useCommand = ({ deviceId, command }: Props) => {
return {
set,
get,
commandLoading,
}
}

Expand All @@ -221,6 +231,8 @@ const isCommandCompleted = ({
}) => {
if (!config) return false

if (config.loading) return false

if (goal) {
return config.value === goal
}
Expand Down
Loading

0 comments on commit 2a7b9dc

Please sign in to comment.